xref: /core/filter/source/msfilter/msdffimp.cxx (revision 4e639c37)
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 <com/sun/star/embed/Aspects.hpp>
21 #include <com/sun/star/embed/XEmbeddedObject.hpp>
22 
23 #include <math.h>
24 #include <limits>
25 #include <limits.h>
26 #include <vector>
27 
28 #include <o3tl/any.hxx>
29 #include <o3tl/safeint.hxx>
30 #include <osl/file.hxx>
31 #include <tools/solar.h>
32 #include <sal/log.hxx>
33 #include <rtl/math.hxx>
34 
35 #include <comphelper/classids.hxx>
36 #include <toolkit/helper/vclunohelper.hxx>
37 #include <unotools/configmgr.hxx>
38 #include <unotools/streamwrap.hxx>
39 #include <comphelper/processfactory.hxx>
40 #include <comphelper/string.hxx>
41 #include <comphelper/seqstream.hxx>
42 #include <comphelper/storagehelper.hxx>
43 #include <comphelper/sequence.hxx>
44 #include <sot/exchange.hxx>
45 #include <sot/storinfo.hxx>
46 #include <vcl/cvtgrf.hxx>
47 #include <vcl/wmf.hxx>
48 #include <vcl/settings.hxx>
49 #include <vcl/vclptr.hxx>
50 #include <vcl/BitmapTools.hxx>
51 #include "viscache.hxx"
52 
53 // SvxItem-Mapping. Is needed to successfully include the SvxItem-Header
54 #include <editeng/eeitem.hxx>
55 #include <editeng/editdata.hxx>
56 #include <tools/stream.hxx>
57 #include <tools/debug.hxx>
58 #include <tools/zcodec.hxx>
59 #include <filter/msfilter/escherex.hxx>
60 #include <basegfx/numeric/ftools.hxx>
61 #include <basegfx/polygon/b2dpolygontools.hxx>
62 #include <com/sun/star/drawing/Position3D.hpp>
63 #include <com/sun/star/drawing/Direction3D.hpp>
64 #include <editeng/charscaleitem.hxx>
65 #include <editeng/kernitem.hxx>
66 #include <vcl/graphicfilter.hxx>
67 #include <tools/urlobj.hxx>
68 #include <vcl/virdev.hxx>
69 #include <vcl/BitmapReadAccess.hxx>
70 #include <sot/storage.hxx>
71 #include <sfx2/docfilt.hxx>
72 #include <sfx2/fcontnr.hxx>
73 #include <svx/xbtmpit.hxx>
74 #include <svx/xsflclit.hxx>
75 #include <svx/xflgrit.hxx>
76 #include <svx/xflftrit.hxx>
77 #include <svx/sdgcpitm.hxx>
78 #include <svx/sdgmoitm.hxx>
79 #include <svx/svdmodel.hxx>
80 #include <svx/svdobj.hxx>
81 #include <svx/svdpage.hxx>
82 #include <svx/svdogrp.hxx>
83 #include <svx/svdograf.hxx>
84 #include <svx/svdotext.hxx>
85 #include <svx/svdorect.hxx>
86 #include <svx/svdoedge.hxx>
87 #include <svx/svdoutl.hxx>
88 #include <svx/svdoole2.hxx>
89 #include <svx/svdopath.hxx>
90 #include <svx/xlntrit.hxx>
91 #include <svx/xfillit0.hxx>
92 #include <svx/xflbmtit.hxx>
93 #include <svx/xflclit.hxx>
94 #include <svx/xfltrit.hxx>
95 #include <svx/xflbmsxy.hxx>
96 #include <svx/xflbmsli.hxx>
97 #include <editeng/frmdir.hxx>
98 #include <editeng/frmdiritem.hxx>
99 #include <svx/svdtrans.hxx>
100 #include <svx/sxenditm.hxx>
101 #include <svx/sdgluitm.hxx>
102 #include <editeng/fhgtitem.hxx>
103 #include <editeng/wghtitem.hxx>
104 #include <editeng/postitem.hxx>
105 #include <editeng/udlnitem.hxx>
106 #include <editeng/crossedoutitem.hxx>
107 #include <editeng/shdditem.hxx>
108 #include <editeng/fontitem.hxx>
109 #include <svx/sxekitm.hxx>
110 #include <svx/xpoly.hxx>
111 #include <svx/xlineit0.hxx>
112 #include <svx/xlncapit.hxx>
113 #include <svx/xlinjoit.hxx>
114 #include <svx/xlndsit.hxx>
115 #include <svx/xlnclit.hxx>
116 #include <svx/xlnwtit.hxx>
117 #include <svx/xlnstwit.hxx>
118 #include <svx/xlnedwit.hxx>
119 #include <svx/xlnstit.hxx>
120 #include <svx/xlnedit.hxx>
121 #include <svx/xlnstcit.hxx>
122 #include <svx/xlnedcit.hxx>
123 #include <svx/sdasitm.hxx>
124 #include <svx/sdggaitm.hxx>
125 #include <svx/sdshcitm.hxx>
126 #include <svx/sdshitm.hxx>
127 #include <svx/sdshtitm.hxx>
128 #include <svx/sdsxyitm.hxx>
129 #include <svx/sdtagitm.hxx>
130 #include <svx/sdtcfitm.hxx>
131 #include <svx/sdtditm.hxx>
132 #include <svx/sdtfsitm.hxx>
133 #include <svx/sdtmfitm.hxx>
134 #include <filter/msfilter/classids.hxx>
135 #include <filter/msfilter/msdffimp.hxx>
136 #include <editeng/outliner.hxx>
137 #include <editeng/outlobj.hxx>
138 #include <com/sun/star/drawing/ShadeMode.hpp>
139 #include <vcl/dibtools.hxx>
140 #include <vcl/svapp.hxx>
141 #include <svx/svdoashp.hxx>
142 #include <svx/EnhancedCustomShapeTypeNames.hxx>
143 #include <svx/EnhancedCustomShapeGeometry.hxx>
144 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
145 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
146 #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
147 #include <com/sun/star/drawing/EnhancedCustomShapeGluePointType.hpp>
148 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
149 #include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
150 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
151 #include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
152 #include <com/sun/star/beans/PropertyValues.hpp>
153 #include <com/sun/star/beans/XPropertySetInfo.hpp>
154 #include <com/sun/star/beans/XPropertySet.hpp>
155 #include <com/sun/star/drawing/ProjectionMode.hpp>
156 #include <svx/EnhancedCustomShape2d.hxx>
157 #include <rtl/ustring.hxx>
158 #include <svtools/embedhlp.hxx>
159 #include <memory>
160 
161 using namespace ::com::sun::star    ;
162 using namespace ::com::sun::star::drawing;
163 using namespace uno                 ;
164 using namespace beans               ;
165 using namespace drawing             ;
166 using namespace container           ;
167 
168 // static counter for OLE-Objects
169 static sal_uInt32 nMSOleObjCntr = 0;
170 #define MSO_OLE_Obj "MSO_OLE_Obj"
171 
172 namespace {
173 
174 struct SvxMSDffBLIPInfo
175 {
176     sal_uLong  nFilePos;    ///< offset of the BLIP in data stream
177     explicit SvxMSDffBLIPInfo(sal_uLong nFPos)
178         : nFilePos(nFPos)
179     {
180     }
181 };
182 
183 }
184 
185 /// the following will be sorted by the order of their appearance:
186 struct SvxMSDffBLIPInfos : public std::vector<SvxMSDffBLIPInfo> {};
187 
188 /************************************************************************/
189 void Impl_OlePres::Write( SvStream & rStm )
190 {
191     WriteClipboardFormat( rStm, SotClipboardFormatId::GDIMETAFILE );
192     rStm.WriteInt32( 4 );       // a TargetDevice that's always empty
193     rStm.WriteUInt32( nAspect );
194     rStm.WriteInt32( -1 );      //L-Index always -1
195     rStm.WriteInt32( nAdvFlags );
196     rStm.WriteInt32( 0 );       //Compression
197     rStm.WriteInt32( aSize.Width() );
198     rStm.WriteInt32( aSize.Height() );
199     sal_uInt64 nPos = rStm.Tell();
200     rStm.WriteInt32( 0 );
201 
202     if( nFormat == SotClipboardFormatId::GDIMETAFILE && pMtf )
203     {
204         // Always to 1/100 mm, until Mtf-Solution found
205         // Assumption (no scaling, no origin translation)
206         DBG_ASSERT( pMtf->GetPrefMapMode().GetScaleX() == Fraction( 1, 1 ),
207                     "x-scale in the Mtf is wrong" );
208         DBG_ASSERT( pMtf->GetPrefMapMode().GetScaleY() == Fraction( 1, 1 ),
209                     "y-scale in the Mtf is wrong" );
210         DBG_ASSERT( pMtf->GetPrefMapMode().GetOrigin() == Point(),
211                     "origin-shift in the Mtf is wrong" );
212         MapUnit nMU = pMtf->GetPrefMapMode().GetMapUnit();
213         if( MapUnit::Map100thMM != nMU )
214         {
215             Size aPrefS( pMtf->GetPrefSize() );
216             Size aS = OutputDevice::LogicToLogic(aPrefS, MapMode(nMU), MapMode(MapUnit::Map100thMM));
217 
218             pMtf->Scale( Fraction( aS.Width(), aPrefS.Width() ),
219                          Fraction( aS.Height(), aPrefS.Height() ) );
220             pMtf->SetPrefMapMode(MapMode(MapUnit::Map100thMM));
221             pMtf->SetPrefSize( aS );
222         }
223         WriteWindowMetafileBits( rStm, *pMtf );
224     }
225     else
226     {
227         OSL_FAIL( "unknown format" );
228     }
229     sal_uInt64 nEndPos = rStm.Tell();
230     rStm.Seek( nPos );
231     rStm.WriteUInt32( nEndPos - nPos - 4 );
232     rStm.Seek( nEndPos );
233 }
234 
235 DffPropertyReader::DffPropertyReader( const SvxMSDffManager& rMan )
236     : rManager(rMan)
237     , mnFix16Angle(0)
238     , mbRotateGranientFillWithAngle(false)
239 {
240     InitializePropSet( DFF_msofbtOPT );
241 }
242 
243 void DffPropertyReader::SetDefaultPropSet( SvStream& rStCtrl, sal_uInt32 nOffsDgg ) const
244 {
245     const_cast<DffPropertyReader*>(this)->pDefaultPropSet.reset();
246     sal_uInt64 nOldPos = rStCtrl.Tell();
247     bool bOk = checkSeek(rStCtrl, nOffsDgg);
248     DffRecordHeader aRecHd;
249     if (bOk)
250         bOk = ReadDffRecordHeader( rStCtrl, aRecHd );
251     if (bOk && aRecHd.nRecType == DFF_msofbtDggContainer)
252     {
253         if ( SvxMSDffManager::SeekToRec( rStCtrl, DFF_msofbtOPT, aRecHd.GetRecEndFilePos() ) )
254         {
255             const_cast<DffPropertyReader*>(this)->pDefaultPropSet.reset( new DffPropSet );
256             ReadDffPropSet( rStCtrl, *pDefaultPropSet );
257         }
258     }
259     rStCtrl.Seek( nOldPos );
260 }
261 
262 #ifdef DBG_CUSTOMSHAPE
263 void DffPropertyReader::ReadPropSet( SvStream& rIn, SvxMSDffClientData* pClientData, sal_uInt32 nShapeId ) const
264 #else
265 void DffPropertyReader::ReadPropSet( SvStream& rIn, SvxMSDffClientData* pClientData ) const
266 #endif
267 {
268     sal_uInt64 nFilePos = rIn.Tell();
269     ReadDffPropSet( rIn, const_cast<DffPropertyReader&>(*this) );
270 
271     if ( IsProperty( DFF_Prop_hspMaster ) )
272     {
273         if ( rManager.SeekToShape( rIn, pClientData, GetPropertyValue( DFF_Prop_hspMaster, 0 ) ) )
274         {
275             DffRecordHeader aRecHd;
276             bool bOk = ReadDffRecordHeader(rIn, aRecHd);
277             if (bOk && SvxMSDffManager::SeekToRec(rIn, DFF_msofbtOPT, aRecHd.GetRecEndFilePos()))
278             {
279                 rIn |= const_cast<DffPropertyReader&>(*this);
280             }
281         }
282     }
283 
284     const_cast<DffPropertyReader*>(this)->mnFix16Angle = Fix16ToAngle( GetPropertyValue( DFF_Prop_Rotation, 0 ) );
285 
286 #ifdef DBG_CUSTOMSHAPE
287 
288     OUString aURLStr;
289 
290     if( osl::FileBase::getFileURLFromSystemPath( OUString("d:\\ashape.dbg"), aURLStr ) == osl::FileBase::E_None )
291     {
292         std::unique_ptr<SvStream> xOut(::utl::UcbStreamHelper::CreateStream( aURLStr, StreamMode::WRITE ));
293 
294         if( xOut )
295         {
296             xOut->Seek( STREAM_SEEK_TO_END );
297 
298             if ( IsProperty( DFF_Prop_adjustValue ) || IsProperty( DFF_Prop_pVertices ) )
299             {
300                 xOut->WriteLine( "" );
301                 OString aString("ShapeId: " + OString::number(nShapeId));
302                 xOut->WriteLine(aString);
303             }
304             for ( sal_uInt32 i = DFF_Prop_adjustValue; i <= DFF_Prop_adjust10Value; i++ )
305             {
306                 if ( IsProperty( i ) )
307                 {
308                     OString aString("Prop_adjustValue" + OString::number( ( i - DFF_Prop_adjustValue ) + 1 ) +
309                                     ":" + OString::number(GetPropertyValue(i)) );
310                     xOut->WriteLine(aString);
311                 }
312             }
313             sal_Int32 i;
314             for ( i = 320; i < 383; i++ )
315             {
316                 if ( ( i >= DFF_Prop_adjustValue ) && ( i <= DFF_Prop_adjust10Value ) )
317                     continue;
318                 if ( IsProperty( i ) )
319                 {
320                     if ( SeekToContent( i, rIn ) )
321                     {
322                         sal_Int32 nLen = (sal_Int32)GetPropertyValue( i );
323                         if ( nLen )
324                         {
325                             xOut->WriteLine( "" );
326                             OStringBuffer aDesc("Property:" + OString::number(i) +
327                                                 "  Size:" + OString::number(nLen));
328                             xOut->WriteLine(aDesc.makeStringAndClear());
329                             sal_Int16   nNumElem, nNumElemMem, nNumSize;
330                             rIn >> nNumElem >> nNumElemMem >> nNumSize;
331                             aDesc.append("Entries: " + OString::number(nNumElem) +
332                                          "  Size:" + OString::number(nNumSize));
333                             xOut->WriteLine(aDesc.makeStringAndClear());
334                             if ( nNumSize < 0 )
335                                 nNumSize = ( ( -nNumSize ) >> 2 );
336                             if ( !nNumSize )
337                                 nNumSize = 16;
338                             nLen -= 6;
339                             while ( nLen > 0 )
340                             {
341                                 for ( sal_uInt32 j = 0; nLen && ( j < ( nNumSize >> 1 ) ); j++ )
342                                 {
343                                     for ( sal_uInt32 k = 0; k < 2; k++ )
344                                     {
345                                         if ( nLen )
346                                         {
347                                             sal_uInt8 nVal;
348                                             rIn >> nVal;
349                                             if ( ( nVal >> 4 ) > 9 )
350                                                 *xOut << (sal_uInt8)( ( nVal >> 4 ) + 'A' - 10 );
351                                             else
352                                                 *xOut << (sal_uInt8)( ( nVal >> 4 ) + '0' );
353 
354                                             if ( ( nVal & 0xf ) > 9 )
355                                                 *xOut << (sal_uInt8)( ( nVal & 0xf ) + 'A' - 10 );
356                                             else
357                                                 *xOut << (sal_uInt8)( ( nVal & 0xf ) + '0' );
358 
359                                             nLen--;
360                                         }
361                                     }
362                                     *xOut << (char)( ' ' );
363                                 }
364                                 xOut->WriteLine( OString() );
365                             }
366                         }
367                     }
368                     else
369                     {
370                         OString aString("Property" + OString::number(i) +
371                                         ":" + OString::number(GetPropertyValue(i)));
372                         xOut->WriteLine(aString);
373                     }
374                 }
375             }
376         }
377     }
378 
379 #endif
380 
381     rIn.Seek( nFilePos );
382 }
383 
384 
385 Degree100 DffPropertyReader::Fix16ToAngle( sal_Int32 nContent )
386 {
387     Degree100 nAngle(0);
388     if ( nContent )
389     {
390         nAngle = Degree100(( static_cast<sal_Int16>( nContent >> 16) * 100L ) + ( ( ( nContent & 0x0000ffff) * 100L ) >> 16 ));
391         nAngle = NormAngle36000( -nAngle );
392     }
393     return nAngle;
394 }
395 
396 DffPropertyReader::~DffPropertyReader()
397 {
398 }
399 
400 static SvStream& operator>>( SvStream& rIn, SvxMSDffConnectorRule& rRule )
401 {
402     sal_uInt32 nRuleId;
403     rIn.ReadUInt32( nRuleId )
404        .ReadUInt32( rRule.nShapeA )
405        .ReadUInt32( rRule.nShapeB )
406        .ReadUInt32( rRule.nShapeC )
407        .ReadUInt32( rRule.ncptiA )
408        .ReadUInt32( rRule.ncptiB );
409 
410     return rIn;
411 }
412 
413 SvxMSDffSolverContainer::SvxMSDffSolverContainer()
414 {
415 }
416 
417 SvxMSDffSolverContainer::~SvxMSDffSolverContainer()
418 {
419 }
420 
421 SvStream& ReadSvxMSDffSolverContainer( SvStream& rIn, SvxMSDffSolverContainer& rContainer )
422 {
423     DffRecordHeader aHd;
424     bool bOk = ReadDffRecordHeader( rIn, aHd );
425     if (bOk && aHd.nRecType == DFF_msofbtSolverContainer)
426     {
427         DffRecordHeader aCRule;
428         auto nEndPos = DffPropSet::SanitizeEndPos(rIn, aHd.GetRecEndFilePos());
429         while ( rIn.good() && ( rIn.Tell() < nEndPos ) )
430         {
431             if (!ReadDffRecordHeader(rIn, aCRule))
432                 break;
433             if ( aCRule.nRecType == DFF_msofbtConnectorRule )
434             {
435                 std::unique_ptr<SvxMSDffConnectorRule> pRule(new SvxMSDffConnectorRule);
436                 rIn >> *pRule;
437                 rContainer.aCList.push_back( std::move(pRule) );
438             }
439             if (!aCRule.SeekToEndOfRecord(rIn))
440                 break;
441         }
442     }
443     return rIn;
444 }
445 
446 void SvxMSDffManager::SolveSolver( const SvxMSDffSolverContainer& rSolver )
447 {
448     size_t i, nCnt;
449     for ( i = 0, nCnt = rSolver.aCList.size(); i < nCnt; i++ )
450     {
451         SvxMSDffConnectorRule* pPtr = rSolver.aCList[ i ].get();
452         if ( pPtr->pCObj )
453         {
454             for ( int nN = 0; nN < 2; nN++ )
455             {
456                 SdrObject*  pO;
457                 sal_uInt32  nC;
458                 ShapeFlag   nSpFlags;
459                 if ( !nN )
460                 {
461                     pO = pPtr->pAObj;
462                     nC = pPtr->ncptiA;
463                     nSpFlags = pPtr->nSpFlagsA;
464                 }
465                 else
466                 {
467                     pO = pPtr->pBObj;
468                     nC = pPtr->ncptiB;
469                     nSpFlags = pPtr->nSpFlagsB;
470                 }
471                 if ( pO )
472                 {
473                     SdrGluePoint aGluePoint;
474                     Reference< XShape > aXShape( pO->getUnoShape(), UNO_QUERY );
475                     Reference< XShape > aXConnector( pPtr->pCObj->getUnoShape(), UNO_QUERY );
476                     SdrGluePointList* pList = pO->ForceGluePointList();
477 
478                     sal_Int32 nId = nC;
479                     SdrInventor nInventor = pO->GetObjInventor();
480 
481                     if( nInventor == SdrInventor::Default )
482                     {
483                         bool bValidGluePoint = false;
484                         sal_uInt32 nObjId = pO->GetObjIdentifier();
485                         switch( nObjId )
486                         {
487                             case OBJ_GRUP :
488                             case OBJ_GRAF :
489                             case OBJ_RECT :
490                             case OBJ_TEXT :
491                             case OBJ_PAGE :
492                             case OBJ_TITLETEXT :
493                             case OBJ_OUTLINETEXT :
494                             {
495                                 if ( nC & 1 )
496                                 {
497                                     if ( nSpFlags & ShapeFlag::FlipH )
498                                         nC ^= 2;    // 1 <-> 3
499                                 }
500                                 else
501                                 {
502                                     if ( nSpFlags & ShapeFlag::FlipV )
503                                         nC ^= 1;    // 0 <-> 2
504                                 }
505                                 switch( nC )
506                                 {
507                                     case 0 :
508                                         nId = 0;    // SdrAlign::VERT_TOP;
509                                     break;
510                                     case 1 :
511                                         nId = 3;    // SdrAlign::HORZ_RIGHT;
512                                     break;
513                                     case 2 :
514                                         nId = 2;    // SdrAlign::VERT_BOTTOM;
515                                     break;
516                                     case 3 :
517                                         nId = 1; // SdrAlign::HORZ_LEFT;
518                                     break;
519                                 }
520                                 if ( nId <= 3 )
521                                     bValidGluePoint = true;
522                             }
523                             break;
524                             case OBJ_POLY :
525                             case OBJ_PLIN :
526                             case OBJ_LINE :
527                             case OBJ_PATHLINE :
528                             case OBJ_PATHFILL :
529                             case OBJ_FREELINE :
530                             case OBJ_FREEFILL :
531                             case OBJ_SPLNLINE :
532                             case OBJ_SPLNFILL :
533                             case OBJ_PATHPOLY :
534                             case OBJ_PATHPLIN :
535                             {
536                                 if (pList)
537                                 {
538                                     if (pList->GetCount() > nC )
539                                     {
540                                         bValidGluePoint = true;
541                                         nId = static_cast<sal_Int32>((*pList)[ static_cast<sal_uInt16>(nC)].GetId() + 3 );
542                                     }
543                                     else
544                                     {
545                                         bool bNotFound = true;
546 
547                                         tools::PolyPolygon aPolyPoly( EscherPropertyContainer::GetPolyPolygon( aXShape ) );
548                                         sal_uInt16 k, j, nPolySize = aPolyPoly.Count();
549                                         if ( nPolySize )
550                                         {
551                                             tools::Rectangle aBoundRect( aPolyPoly.GetBoundRect() );
552                                             if ( aBoundRect.GetWidth() && aBoundRect.GetHeight() )
553                                             {
554                                                 sal_uInt32  nPointCount = 0;
555                                                 for ( k = 0; bNotFound && ( k < nPolySize ); k++ )
556                                                 {
557                                                     const tools::Polygon& rPolygon = aPolyPoly.GetObject( k );
558                                                     for ( j = 0; bNotFound && ( j < rPolygon.GetSize() ); j++ )
559                                                     {
560                                                         PolyFlags eFlags = rPolygon.GetFlags( j );
561                                                         if ( eFlags == PolyFlags::Normal )
562                                                         {
563                                                             if ( nC == nPointCount )
564                                                             {
565                                                                 const Point& rPoint = rPolygon.GetPoint( j );
566                                                                 double fXRel = rPoint.X() - aBoundRect.Left();
567                                                                 double fYRel = rPoint.Y() - aBoundRect.Top();
568                                                                 sal_Int32 nWidth = aBoundRect.GetWidth();
569                                                                 if ( !nWidth )
570                                                                     nWidth = 1;
571                                                                 sal_Int32 nHeight= aBoundRect.GetHeight();
572                                                                 if ( !nHeight )
573                                                                     nHeight = 1;
574                                                                 fXRel /= static_cast<double>(nWidth);
575                                                                 fXRel *= 10000;
576                                                                 fYRel /= static_cast<double>(nHeight);
577                                                                 fYRel *= 10000;
578                                                                 aGluePoint.SetPos( Point( static_cast<sal_Int32>(fXRel), static_cast<sal_Int32>(fYRel) ) );
579                                                                 aGluePoint.SetPercent( true );
580                                                                 aGluePoint.SetAlign( SdrAlign::VERT_TOP | SdrAlign::HORZ_LEFT );
581                                                                 aGluePoint.SetEscDir( SdrEscapeDirection::SMART );
582                                                                 nId = static_cast<sal_Int32>((*pList)[ pList->Insert( aGluePoint ) ].GetId() + 3 );
583                                                                 bNotFound = false;
584                                                             }
585                                                             nPointCount++;
586                                                         }
587                                                     }
588                                                 }
589                                             }
590                                         }
591                                         if ( !bNotFound )
592                                         {
593                                             bValidGluePoint = true;
594                                         }
595                                     }
596                                 }
597                             }
598                             break;
599 
600                             case OBJ_CUSTOMSHAPE :
601                             {
602                                 const SfxPoolItem& aCustomShape =  static_cast<SdrObjCustomShape*>(pO)->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
603                                 SdrCustomShapeGeometryItem aGeometryItem( static_cast<const SdrCustomShapeGeometryItem&>(aCustomShape) );
604                                 const OUString sPath( "Path" );
605                                 sal_Int16 nGluePointType = EnhancedCustomShapeGluePointType::SEGMENTS;
606                                 css::uno::Any* pAny = aGeometryItem.GetPropertyValueByName( sPath, "GluePointType" );
607                                 if ( pAny )
608                                     *pAny >>= nGluePointType;
609                                 else
610                                 {
611                                     OUString sShapeType;
612                                     pAny = aGeometryItem.GetPropertyValueByName( "Type" );
613                                     if ( pAny )
614                                         *pAny >>= sShapeType;
615                                     MSO_SPT eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType );
616                                     nGluePointType = GetCustomShapeConnectionTypeDefault( eSpType );
617                                 }
618                                 if ( nGluePointType == EnhancedCustomShapeGluePointType::CUSTOM )
619                                 {
620                                     if ( pList && ( pList->GetCount() > nC ) )
621                                     {
622                                         bValidGluePoint = true;
623                                         nId = static_cast<sal_Int32>((*pList)[ static_cast<sal_uInt16>(nC)].GetId() + 3 );
624                                     }
625                                 }
626                                 else if ( nGluePointType == EnhancedCustomShapeGluePointType::RECT )
627                                 {
628                                     if ( nC & 1 )
629                                     {
630                                         if ( nSpFlags & ShapeFlag::FlipH )
631                                             nC ^= 2;    // 1 <-> 3
632                                     }
633                                     else
634                                     {
635                                         if ( nSpFlags & ShapeFlag::FlipV )
636                                             nC ^= 1;    // 0 <-> 2
637                                     }
638                                     switch( nC )
639                                     {
640                                         case 0 :
641                                             nId = 0;    // SdrAlign::VERT_TOP;
642                                         break;
643                                         case 1 :
644                                             nId = 3;    // SdrAlign::HORZ_RIGHT;
645                                         break;
646                                         case 2 :
647                                             nId = 2;    // SdrAlign::VERT_BOTTOM;
648                                         break;
649                                         case 3 :
650                                             nId = 1; // SdrAlign::HORZ_LEFT;
651                                         break;
652                                     }
653                                     if ( nId <= 3 )
654                                         bValidGluePoint = true;
655                                 }
656                                 else if ( nGluePointType == EnhancedCustomShapeGluePointType::SEGMENTS )
657                                 {
658                                     sal_uInt32 nPt = nC;
659                                     css::uno::Sequence< css::drawing::EnhancedCustomShapeSegment > aSegments;
660                                     pAny = aGeometryItem.GetPropertyValueByName( sPath, "Segments" );
661                                     if ( pAny && (*pAny >>= aSegments) )
662                                     {
663                                         nPt = 0;
664                                         for ( sal_Int32 k = 1; nC && ( k < aSegments.getLength() ); k++ )
665                                         {
666                                             sal_Int16 j, nCnt2 = aSegments[ k ].Count;
667                                             if ( aSegments[ k ].Command != EnhancedCustomShapeSegmentCommand::UNKNOWN )
668                                             {
669                                                 for ( j = 0; nC && ( j < nCnt2 ); j++ )
670                                                 {
671                                                     switch( aSegments[ k ].Command )
672                                                     {
673                                                         case EnhancedCustomShapeSegmentCommand::ENDSUBPATH :
674                                                         case EnhancedCustomShapeSegmentCommand::CLOSESUBPATH :
675                                                         case EnhancedCustomShapeSegmentCommand::LINETO :
676                                                         case EnhancedCustomShapeSegmentCommand::MOVETO :
677                                                         {
678                                                             nC--;
679                                                             nPt++;
680                                                         }
681                                                         break;
682                                                         case EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX :
683                                                         case EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY :
684                                                         break;
685 
686                                                         case EnhancedCustomShapeSegmentCommand::CURVETO :
687                                                         {
688                                                             nC--;
689                                                             nPt += 3;
690                                                         }
691                                                         break;
692 
693                                                         case EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO :
694                                                         case EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE :
695                                                         {
696                                                             nC--;
697                                                             nPt += 3;
698                                                         }
699                                                         break;
700                                                         case EnhancedCustomShapeSegmentCommand::ARCTO :
701                                                         case EnhancedCustomShapeSegmentCommand::ARC :
702                                                         case EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO :
703                                                         case EnhancedCustomShapeSegmentCommand::CLOCKWISEARC :
704                                                         {
705                                                             nC--;
706                                                             nPt += 4;
707                                                         }
708                                                         break;
709                                                     }
710                                                 }
711                                             }
712                                         }
713                                     }
714                                     pAny = aGeometryItem.GetPropertyValueByName( sPath, "Coordinates" );
715                                     if ( pAny )
716                                     {
717                                         css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aCoordinates;
718                                         *pAny >>= aCoordinates;
719                                         if ( nPt < o3tl::make_unsigned(aCoordinates.getLength()) )
720                                         {
721                                             nId = 4;
722                                             css::drawing::EnhancedCustomShapeParameterPair& rPara = aCoordinates[ nPt ];
723                                             sal_Int32 nX = 0, nY = 0;
724                                             if ( ( rPara.First.Value >>= nX ) && ( rPara.Second.Value >>= nY ) )
725                                             {
726                                                 const OUString sGluePoints( "GluePoints" );
727                                                 css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aGluePoints;
728                                                 pAny = aGeometryItem.GetPropertyValueByName( sPath, sGluePoints );
729                                                 if ( pAny )
730                                                     *pAny >>= aGluePoints;
731                                                 sal_Int32 nGluePoints = aGluePoints.getLength();
732                                                 aGluePoints.realloc( nGluePoints + 1 );
733                                                 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aGluePoints[ nGluePoints ].First, nX );
734                                                 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aGluePoints[ nGluePoints ].Second, nY );
735                                                 PropertyValue aProp;
736                                                 aProp.Name = sGluePoints;
737                                                 aProp.Value <<= aGluePoints;
738                                                 aGeometryItem.SetPropertyValue( sPath, aProp );
739                                                 bValidGluePoint = true;
740                                                 static_cast<SdrObjCustomShape*>(pO)->SetMergedItem( aGeometryItem );
741                                                 SdrGluePointList* pLst = pO->ForceGluePointList();
742                                                 if ( pLst->GetCount() > nGluePoints )
743                                                     nId = static_cast<sal_Int32>((*pLst)[ static_cast<sal_uInt16>(nGluePoints) ].GetId() + 3 );
744                                             }
745                                         }
746                                     }
747                                 }
748                             }
749                             break;
750                         }
751                         if ( bValidGluePoint )
752                         {
753                             Reference< XPropertySet > xPropSet( aXConnector, UNO_QUERY );
754                             if ( xPropSet.is() )
755                             {
756                                 if ( nN )
757                                 {
758                                     OUString aPropName( "EndShape" );
759                                     SetPropValue( Any(aXShape), xPropSet, aPropName );
760                                     aPropName = "EndGluePointIndex";
761                                     SetPropValue( Any(nId), xPropSet, aPropName );
762                                 }
763                                 else
764                                 {
765                                     OUString aPropName( "StartShape" );
766                                     SetPropValue( Any(aXShape), xPropSet, aPropName );
767                                     aPropName = "StartGluePointIndex";
768                                     SetPropValue( Any(nId), xPropSet, aPropName );
769                                 }
770 
771                                 // Not sure what this is good for, repaint or broadcast of object change.
772                                 //( Thus I am adding repaint here
773                                 pO->SetChanged();
774                                 pO->BroadcastObjectChange();
775                             }
776                         }
777                     }
778                 }
779             }
780         }
781     }
782 }
783 
784 static basegfx::B2DPolyPolygon GetLineArrow( const sal_Int32 nLineWidth, const sal_uInt32 eLineEnd,
785     const sal_uInt32 eLineWidth, const sal_uInt32 eLineLength,
786     sal_Int32& rnArrowWidth, bool& rbArrowCenter,
787     OUString& rsArrowName, bool bScaleArrow )
788 {
789     basegfx::B2DPolyPolygon aRetPolyPoly;
790     // 70 100mm = 2pt = 40 twip. In MS, line width less than 2pt has the same size arrow as 2pt
791     //If the unit is twip. Make all use this unit especially the critical value 70/40.
792     sal_Int32   nLineWidthCritical = bScaleArrow ? 40 : 70;
793     double      fLineWidth = nLineWidth < nLineWidthCritical ? nLineWidthCritical : nLineWidth;
794 
795     double      fLengthMul, fWidthMul;
796     sal_Int32   nLineNumber;
797     switch( eLineLength )
798     {
799         default :
800         case mso_lineMediumLenArrow     : fLengthMul = 3.0; nLineNumber = 2; break;
801         case mso_lineShortArrow         : fLengthMul = 2.0; nLineNumber = 1; break;
802         case mso_lineLongArrow          : fLengthMul = 5.0; nLineNumber = 3; break;
803     }
804     switch( eLineWidth )
805     {
806         default :
807         case mso_lineMediumWidthArrow   : fWidthMul = 3.0; nLineNumber += 3; break;
808         case mso_lineNarrowArrow        : fWidthMul = 2.0; break;
809         case mso_lineWideArrow          : fWidthMul = 5.0; nLineNumber += 6; break;
810     }
811 
812     rbArrowCenter = false;
813     OUStringBuffer aArrowName;
814     switch ( eLineEnd )
815     {
816         case mso_lineArrowEnd :
817         {
818             basegfx::B2DPolygon aTriangle;
819             aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50, 0.0 ));
820             aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth, fLengthMul * fLineWidth ));
821             aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth ));
822             aTriangle.setClosed(true);
823             aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle);
824             aArrowName.append("msArrowEnd ");
825         }
826         break;
827 
828         case mso_lineArrowOpenEnd :
829         {
830             switch( eLineLength )
831             {
832                 default :
833                 case mso_lineMediumLenArrow     : fLengthMul = 4.5; break;
834                 case mso_lineShortArrow         : fLengthMul = 3.5; break;
835                 case mso_lineLongArrow          : fLengthMul = 6.0; break;
836             }
837             switch( eLineWidth )
838             {
839                 default :
840                 case mso_lineMediumWidthArrow   : fWidthMul = 4.5; break;
841                 case mso_lineNarrowArrow        : fWidthMul = 3.5; break;
842                 case mso_lineWideArrow          : fWidthMul = 6.0; break;
843             }
844             basegfx::B2DPolygon aTriangle;
845             aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , 0.0 ));
846             aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth, fLengthMul * fLineWidth * 0.91 ));
847             aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.85, fLengthMul * fLineWidth ));
848             aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50, fLengthMul * fLineWidth * 0.36 ));
849             aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.15, fLengthMul * fLineWidth ));
850             aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth * 0.91 ));
851             aTriangle.setClosed(true);
852             aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle);
853             aArrowName.append("msArrowOpenEnd ");
854         }
855         break;
856         case mso_lineArrowStealthEnd :
857         {
858             basegfx::B2DPolygon aTriangle;
859             aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , 0.0 ));
860             aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth , fLengthMul * fLineWidth ));
861             aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , fLengthMul * fLineWidth * 0.60 ));
862             aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth ));
863             aTriangle.setClosed(true);
864             aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle);
865             aArrowName.append("msArrowStealthEnd ");
866         }
867         break;
868         case mso_lineArrowDiamondEnd :
869         {
870             basegfx::B2DPolygon aTriangle;
871             aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , 0.0 ));
872             aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth , fLengthMul * fLineWidth * 0.50 ));
873             aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , fLengthMul * fLineWidth ));
874             aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth * 0.50 ));
875             aTriangle.setClosed(true);
876             aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle);
877             rbArrowCenter = true;
878             aArrowName.append("msArrowDiamondEnd ");
879         }
880         break;
881         case mso_lineArrowOvalEnd :
882         {
883             aRetPolyPoly = basegfx::B2DPolyPolygon(
884                             XPolygon(
885                                 Point( static_cast<sal_Int32>( fWidthMul * fLineWidth * 0.50 ), 0 ),
886                                 static_cast<sal_Int32>( fWidthMul * fLineWidth * 0.50 ),
887                                 static_cast<sal_Int32>( fLengthMul * fLineWidth * 0.50 ),
888                                 0_deg100, 36000_deg100 ).getB2DPolygon() );
889             rbArrowCenter = true;
890             aArrowName.append("msArrowOvalEnd ");
891         }
892         break;
893         default: break;
894     }
895     aArrowName.append(nLineNumber);
896     rsArrowName = aArrowName.makeStringAndClear();
897     rnArrowWidth = static_cast<sal_Int32>( fLineWidth * fWidthMul );
898 
899     return aRetPolyPoly;
900 }
901 
902 void DffPropertyReader::ApplyLineAttributes( SfxItemSet& rSet, const MSO_SPT eShapeType ) const // #i28269#
903 {
904     sal_uInt32 nLineFlags(GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 ));
905 
906     if(!IsHardAttribute( DFF_Prop_fLine ) && !IsCustomShapeStrokedByDefault( eShapeType ))
907     {
908         nLineFlags &= ~0x08;
909     }
910 
911     if ( nLineFlags & 8 )
912     {
913         // Line Attributes
914         sal_Int32 nLineWidth = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_lineWidth, 9525 ));
915 
916         // support LineCap
917         auto eLineCap = GetPropertyValue(DFF_Prop_lineEndCapStyle, mso_lineEndCapFlat);
918 
919         switch(eLineCap)
920         {
921             default: /* case mso_lineEndCapFlat */
922             {
923                 // no need to set, it is the default. If this changes, this needs to be activated
924                 // rSet.Put(XLineCapItem(css::drawing::LineCap_BUTT));
925                 break;
926             }
927             case mso_lineEndCapRound:
928             {
929                 rSet.Put(XLineCapItem(css::drawing::LineCap_ROUND));
930                 break;
931             }
932             case mso_lineEndCapSquare:
933             {
934                 rSet.Put(XLineCapItem(css::drawing::LineCap_SQUARE));
935                 break;
936             }
937         }
938 
939         auto eLineDashing = GetPropertyValue( DFF_Prop_lineDashing, mso_lineSolid);
940         if (eLineDashing == mso_lineSolid || nLineWidth < 0)
941             rSet.Put(XLineStyleItem( drawing::LineStyle_SOLID ) );
942         else
943         {
944             // Despite of naming "dot" and "dash", that are all dashes and a "dot" can be longer
945             // than a "dash". The naming indicates the order, "dot" is always the first dash and
946             // "dash" is always the second dash. MS Office always starts with the longer dash, so
947             // set it here accordingly.
948             // The preset from binary is essentially the same as from OOXML. So here the same
949             // setting is used as in oox import. The comment corresponds to
950             // "dots, dotLen, dashes, dashLen, distance" there.
951             // MS Office uses always relative length, so no need to consider nLineWidth
952             // here. Values are of kind 300 for 300% in css::drawing::DashStyle, for example.
953 
954             sal_uInt16  nDots = 1; // in all cases, "solid" is treated above
955             // initialize, will be changed if necessary
956             sal_uInt32  nDotLen = 300;
957             sal_uInt16  nDashes = 0;
958             sal_uInt32  nDashLen = 0;
959             sal_uInt32  nDistance = 300;
960             switch ( eLineDashing )
961             {
962                 default:
963                 case mso_lineDotSys : // 1 1 0 0 1
964                 {
965                     nDotLen =100;
966                     nDistance = 100;
967                 }
968                 break;
969 
970                 case mso_lineDashGEL : // 1 4 0 0 3
971                 {
972                     nDotLen = 400;
973                 }
974                 break;
975 
976                 case mso_lineDashDotGEL : // 1 4 1 1 3
977                 {
978                     nDotLen = 400;
979                     nDashes = 1;
980                     nDashLen = 100;
981                 }
982                 break;
983 
984                 case mso_lineLongDashGEL : // 1 8 0 0 3
985                 {
986                     nDotLen = 800;
987                 }
988                 break;
989 
990                 case mso_lineLongDashDotGEL : // 1 8 1 1 3
991                 {
992                     nDotLen = 800;
993                     nDashes = 1;
994                     nDashLen = 100;
995                 }
996                 break;
997 
998                 case mso_lineLongDashDotDotGEL: // 1 8 2 1 3
999                 {
1000                     nDotLen = 800;
1001                     nDashes = 2;
1002                     nDashLen = 100;
1003                 }
1004                 break;
1005 
1006                 case mso_lineDotGEL: // 1 1 0 0 3
1007                 {
1008                     nDotLen = 100;
1009                 }
1010                 break;
1011 
1012                 case mso_lineDashSys: // 1 3 0 0 1
1013                 {
1014                     nDistance = 100;
1015                 }
1016                 break;
1017 
1018                 case mso_lineDashDotSys: // 1 3 1 1 1
1019                 {
1020                     nDashes = 1;
1021                     nDashLen = 100;
1022                     nDistance = 100;
1023                 }
1024                 break;
1025 
1026                 case mso_lineDashDotDotSys: // 1 3 2 1 1
1027                 {
1028                     nDashes = 2;
1029                     nDashLen = 100;
1030                     nDistance = 100;
1031                 }
1032                 break;
1033             }
1034             rSet.Put( XLineDashItem( OUString(), XDash( css::drawing::DashStyle_RECTRELATIVE, nDots, nDotLen, nDashes, nDashLen, nDistance ) ) );
1035             rSet.Put( XLineStyleItem( drawing::LineStyle_DASH ) );
1036         }
1037         rSet.Put( XLineColorItem( OUString(), rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_lineColor, 0 ) ) ) );
1038         if ( IsProperty( DFF_Prop_lineOpacity ) )
1039         {
1040             double nTrans = GetPropertyValue(DFF_Prop_lineOpacity, 0x10000);
1041             nTrans = (nTrans * 100) / 65536;
1042             rSet.Put(XLineTransparenceItem(
1043                 sal_uInt16(100 - ::rtl::math::round(nTrans))));
1044         }
1045 
1046         rManager.ScaleEmu( nLineWidth );
1047         rSet.Put( XLineWidthItem( nLineWidth ) );
1048 
1049         // SJ: LineJoint (setting each time a line is set, because our internal joint type has another default)
1050         MSO_LineJoin eLineJointDefault = mso_lineJoinMiter;
1051         if ( eShapeType == mso_sptMin )
1052             eLineJointDefault = mso_lineJoinRound;
1053         auto eLineJoint = GetPropertyValue(DFF_Prop_lineJoinStyle, eLineJointDefault);
1054         css::drawing::LineJoint eXLineJoint( css::drawing::LineJoint_MITER );
1055         if ( eLineJoint == mso_lineJoinBevel )
1056             eXLineJoint = css::drawing::LineJoint_BEVEL;
1057         else if ( eLineJoint == mso_lineJoinRound )
1058             eXLineJoint = css::drawing::LineJoint_ROUND;
1059         rSet.Put( XLineJointItem( eXLineJoint ) );
1060 
1061         if ( nLineFlags & 0x10 )
1062         {
1063             bool bScaleArrows = rManager.pSdrModel->GetScaleUnit() == MapUnit::MapTwip;
1064 
1065             // LineStart
1066 
1067             if ( IsProperty( DFF_Prop_lineStartArrowhead ) )
1068             {
1069                 auto eLineEnd = GetPropertyValue(DFF_Prop_lineStartArrowhead, 0);
1070                 auto eWidth = GetPropertyValue(DFF_Prop_lineStartArrowWidth, mso_lineMediumWidthArrow);
1071                 auto eLength = GetPropertyValue(DFF_Prop_lineStartArrowLength, mso_lineMediumLenArrow);
1072 
1073                 sal_Int32   nArrowWidth;
1074                 bool        bArrowCenter;
1075                 OUString    aArrowName;
1076                 basegfx::B2DPolyPolygon aPolyPoly(GetLineArrow( nLineWidth, eLineEnd, eWidth, eLength, nArrowWidth, bArrowCenter, aArrowName, bScaleArrows ));
1077 
1078                 rSet.Put( XLineStartWidthItem( nArrowWidth ) );
1079                 rSet.Put( XLineStartItem( aArrowName, aPolyPoly) );
1080                 rSet.Put( XLineStartCenterItem( bArrowCenter ) );
1081             }
1082 
1083             // LineEnd
1084 
1085             if ( IsProperty( DFF_Prop_lineEndArrowhead ) )
1086             {
1087                 auto eLineEnd = GetPropertyValue(DFF_Prop_lineEndArrowhead, 0);
1088                 auto eWidth = GetPropertyValue(DFF_Prop_lineEndArrowWidth, mso_lineMediumWidthArrow);
1089                 auto eLength = GetPropertyValue(DFF_Prop_lineEndArrowLength, mso_lineMediumLenArrow);
1090 
1091                 sal_Int32   nArrowWidth;
1092                 bool        bArrowCenter;
1093                 OUString    aArrowName;
1094                 basegfx::B2DPolyPolygon aPolyPoly(GetLineArrow( nLineWidth, eLineEnd, eWidth, eLength, nArrowWidth, bArrowCenter, aArrowName, bScaleArrows ));
1095 
1096                 rSet.Put( XLineEndWidthItem( nArrowWidth ) );
1097                 rSet.Put( XLineEndItem( aArrowName, aPolyPoly ) );
1098                 rSet.Put( XLineEndCenterItem( bArrowCenter ) );
1099             }
1100         }
1101     }
1102     else
1103         rSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
1104 }
1105 
1106 namespace {
1107 
1108 struct ShadeColor
1109 {
1110     Color       aColor;
1111     double      fDist;
1112 
1113     ShadeColor( const Color& rC, double fR ) : aColor( rC ), fDist( fR ) {};
1114 };
1115 
1116 }
1117 
1118 static void GetShadeColors( const SvxMSDffManager& rManager, const DffPropertyReader& rProperties, SvStream& rIn, std::vector< ShadeColor >& rShadeColors )
1119 {
1120     sal_uInt64 nPos = rIn.Tell();
1121     if ( rProperties.IsProperty( DFF_Prop_fillShadeColors ) )
1122     {
1123         sal_uInt16 i = 0, nNumElem = 0;
1124         bool bOk = false;
1125         if (rProperties.SeekToContent(DFF_Prop_fillShadeColors, rIn))
1126         {
1127             sal_uInt16 nNumElemReserved = 0, nSize = 0;
1128             rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemReserved ).ReadUInt16( nSize );
1129             //sanity check that the stream is long enough to fulfill nNumElem * 2 sal_Int32s
1130             bOk = rIn.remainingSize() / (2*sizeof(sal_Int32)) >= nNumElem;
1131         }
1132         if (bOk)
1133         {
1134             for ( ; i < nNumElem; i++ )
1135             {
1136                 sal_Int32 nColor(0);
1137                 sal_Int32 nDist(0);
1138 
1139                 rIn.ReadInt32( nColor ).ReadInt32( nDist );
1140                 rShadeColors.emplace_back( rManager.MSO_CLR_ToColor( nColor, DFF_Prop_fillColor ), 1.0 - ( nDist / 65536.0 ) );
1141             }
1142         }
1143     }
1144     if ( rShadeColors.empty() )
1145     {
1146         rShadeColors.emplace_back( rManager.MSO_CLR_ToColor( rProperties.GetPropertyValue( DFF_Prop_fillBackColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillBackColor ), 0 );
1147         rShadeColors.emplace_back( rManager.MSO_CLR_ToColor( rProperties.GetPropertyValue( DFF_Prop_fillColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillColor ), 1 );
1148     }
1149     rIn.Seek( nPos );
1150 }
1151 
1152 static void ApplyRectangularGradientAsBitmap( const SvxMSDffManager& rManager, SvStream& rIn, SfxItemSet& rSet, const std::vector< ShadeColor >& rShadeColors, const DffObjData& rObjData, Degree100 nFix16Angle )
1153 {
1154     Size aBitmapSizePixel( static_cast< sal_Int32 >( ( rObjData.aBoundRect.GetWidth() / 2540.0 ) * 90.0 ),      // we will create a bitmap with 90 dpi
1155                            static_cast< sal_Int32 >( ( rObjData.aBoundRect.GetHeight() / 2540.0 ) * 90.0 ) );
1156     if (aBitmapSizePixel.IsEmpty() || aBitmapSizePixel.Width() > 1024 || aBitmapSizePixel.Height() > 1024)
1157         return;
1158 
1159     double fFocusX = rManager.GetPropertyValue( DFF_Prop_fillToRight, 0 ) / 65536.0;
1160     double fFocusY = rManager.GetPropertyValue( DFF_Prop_fillToBottom, 0 ) / 65536.0;
1161 
1162     vcl::bitmap::RawBitmap aBitmap(aBitmapSizePixel, 24);
1163 
1164     for ( tools::Long nY = 0; nY < aBitmapSizePixel.Height(); nY++ )
1165     {
1166         for ( tools::Long nX = 0; nX < aBitmapSizePixel.Width(); nX++ )
1167         {
1168             double fX = static_cast< double >( nX ) / aBitmapSizePixel.Width();
1169             double fY = static_cast< double >( nY ) / aBitmapSizePixel.Height();
1170 
1171             double fD, fDist;
1172             if ( fX < fFocusX )
1173             {
1174                 if ( fY < fFocusY )
1175                 {
1176                     if ( fX > fY )
1177                     {
1178                         fDist = fY;
1179                         fD = fFocusY;
1180                     }
1181                     else
1182                     {
1183                         fDist = fX;
1184                         fD = fFocusX;
1185                     }
1186                 }
1187                 else
1188                 {
1189                     if ( fX > ( 1 - fY ) )
1190                     {
1191                         fDist = 1 - fY;
1192                         fD = 1 - fFocusY;
1193                     }
1194                     else
1195                     {
1196                         fDist = fX;
1197                         fD = fFocusX;
1198                     }
1199                 }
1200             }
1201             else
1202             {
1203                 if ( fY < fFocusY )
1204                 {
1205                     if ( ( 1 - fX ) > fY )
1206                     {
1207                         fDist = fY;
1208                         fD = fFocusY;
1209                     }
1210                     else
1211                     {
1212                         fDist = 1 - fX;
1213                         fD = 1 - fFocusX;
1214                     }
1215                 }
1216                 else
1217                 {
1218                     if ( ( 1 - fX ) > ( 1 - fY ) )
1219                     {
1220                         fDist = 1 - fY;
1221                         fD = 1 - fFocusY;
1222                     }
1223                     else
1224                     {
1225                         fDist = 1 - fX;
1226                         fD = 1 - fFocusX;
1227                     }
1228                 }
1229             }
1230             if ( fD != 0.0 )
1231                 fDist /= fD;
1232 
1233             double fA = 0.0;
1234             Color aColorA = rShadeColors.front().aColor;
1235             double fB = 1.0;
1236             Color aColorB( aColorA );
1237             for ( const auto& rShadeColor : rShadeColors )
1238             {
1239                 if ( fA <= rShadeColor.fDist && rShadeColor.fDist <= fDist )
1240                 {
1241                     fA = rShadeColor.fDist;
1242                     aColorA = rShadeColor.aColor;
1243                 }
1244                 if ( fDist < rShadeColor.fDist && rShadeColor.fDist <= fB )
1245                 {
1246                     fB = rShadeColor.fDist;
1247                     aColorB = rShadeColor.aColor;
1248                 }
1249             }
1250             double fRed = aColorA.GetRed(), fGreen = aColorA.GetGreen(), fBlue = aColorA.GetBlue();
1251             double fD1 = fB - fA;
1252             if ( fD1 != 0.0 )
1253             {
1254                 fRed   += ( ( ( fDist - fA ) * ( aColorB.GetRed() - aColorA.GetRed() ) ) / fD1 );       // + aQuantErrCurrScan[ nX ].fRed;
1255                 fGreen += ( ( ( fDist - fA ) * ( aColorB.GetGreen() - aColorA.GetGreen() ) ) / fD1 );   // + aQuantErrCurrScan[ nX ].fGreen;
1256                 fBlue  += ( ( ( fDist - fA ) * ( aColorB.GetBlue() - aColorA.GetBlue() ) ) / fD1 );     // + aQuantErrCurrScan[ nX ].fBlue;
1257             }
1258             sal_Int16 nRed   = static_cast< sal_Int16 >( fRed   + 0.5 );
1259             sal_Int16 nGreen = static_cast< sal_Int16 >( fGreen + 0.5 );
1260             sal_Int16 nBlue  = static_cast< sal_Int16 >( fBlue  + 0.5 );
1261             if ( nRed < 0 )
1262                 nRed = 0;
1263             if ( nRed > 255 )
1264                 nRed = 255;
1265             if ( nGreen < 0 )
1266                 nGreen = 0;
1267             if ( nGreen > 255 )
1268                 nGreen = 255;
1269             if ( nBlue < 0 )
1270                 nBlue = 0;
1271             if ( nBlue > 255 )
1272                 nBlue = 255;
1273 
1274             aBitmap.SetPixel(nY, nX, Color(static_cast<sal_Int8>(nRed), static_cast<sal_Int8>(nGreen), static_cast<sal_Int8>(nBlue)));
1275         }
1276     }
1277     BitmapEx aBitmapEx = vcl::bitmap::CreateFromData( std::move(aBitmap) );
1278 
1279     if ( nFix16Angle )
1280     {
1281         bool bRotateWithShape = true;   // sal_True seems to be default
1282         sal_uInt64 nPos = rIn.Tell();
1283         if ( const_cast< SvxMSDffManager& >( rManager ).maShapeRecords.SeekToContent( rIn, DFF_msofbtUDefProp, SEEK_FROM_CURRENT_AND_RESTART ) )
1284         {
1285             const_cast< SvxMSDffManager& >( rManager ).maShapeRecords.Current()->SeekToBegOfRecord( rIn );
1286             DffPropertyReader aSecPropSet( rManager );
1287             aSecPropSet.ReadPropSet( rIn, nullptr );
1288             sal_Int32 nSecFillProperties = aSecPropSet.GetPropertyValue( DFF_Prop_fNoFillHitTest, 0x200020 );
1289             bRotateWithShape = ( nSecFillProperties & 0x0020 );
1290         }
1291         rIn.Seek( nPos );
1292         if ( bRotateWithShape )
1293         {
1294             // convert from 100th to 10th degrees
1295             aBitmapEx.Rotate( toDegree10(nFix16Angle), rShadeColors[ 0 ].aColor );
1296 
1297             BmpMirrorFlags nMirrorFlags = BmpMirrorFlags::NONE;
1298             if ( rObjData.nSpFlags & ShapeFlag::FlipV )
1299                 nMirrorFlags |= BmpMirrorFlags::Vertical;
1300             if ( rObjData.nSpFlags & ShapeFlag::FlipH )
1301                 nMirrorFlags |= BmpMirrorFlags::Horizontal;
1302             if ( nMirrorFlags != BmpMirrorFlags::NONE )
1303                 aBitmapEx.Mirror( nMirrorFlags );
1304         }
1305     }
1306 
1307     rSet.Put(XFillBmpTileItem(false));
1308     rSet.Put(XFillBitmapItem(OUString(), Graphic(aBitmapEx)));
1309 }
1310 
1311 void DffPropertyReader::ApplyFillAttributes( SvStream& rIn, SfxItemSet& rSet, const DffObjData& rObjData ) const
1312 {
1313     sal_uInt32 nFillFlags(GetPropertyValue( DFF_Prop_fNoFillHitTest, 0 ));
1314 
1315     std::vector< ShadeColor > aShadeColors;
1316     GetShadeColors( rManager, *this, rIn, aShadeColors );
1317 
1318     if(!IsHardAttribute( DFF_Prop_fFilled ) && !IsCustomShapeFilledByDefault( rObjData.eShapeType ))
1319     {
1320         nFillFlags &= ~0x10;
1321     }
1322 
1323     if ( nFillFlags & 0x10 )
1324     {
1325         auto eMSO_FillType = GetPropertyValue(DFF_Prop_fillType, mso_fillSolid);
1326         drawing::FillStyle eXFill = drawing::FillStyle_NONE;
1327         switch( eMSO_FillType )
1328         {
1329             case mso_fillSolid :            // Fill with a solid color
1330                 eXFill = drawing::FillStyle_SOLID;
1331             break;
1332             case mso_fillPattern :          // Fill with a pattern (bitmap)
1333             case mso_fillTexture :          // A texture (pattern with its own color map)
1334             case mso_fillPicture :          // Center a picture in the shape
1335                 eXFill = drawing::FillStyle_BITMAP;
1336             break;
1337             case mso_fillShadeCenter :      // Shade from bounding rectangle to end point
1338             {
1339                 //If it is imported as a bitmap, it will not work well with transparency especially 100
1340                 //But the gradient look well comparing with imported as gradient. And rotate with shape
1341                 //also works better. So here just keep it.
1342                 if ( rObjData.aBoundRect.IsEmpty() )// size of object needed to be able
1343                     eXFill = drawing::FillStyle_GRADIENT;        // to create a bitmap substitution
1344                 else
1345                     eXFill = drawing::FillStyle_BITMAP;
1346             }
1347             break;
1348             case mso_fillShade :            // Shade from start to end points
1349             case mso_fillShadeShape :       // Shade from shape outline to end point
1350             case mso_fillShadeScale :       // Similar to mso_fillShade, but the fillAngle
1351             case mso_fillShadeTitle :       // special type - shade to title ---  for PP
1352                 eXFill = drawing::FillStyle_GRADIENT;
1353             break;
1354 //          case mso_fillBackground :       // Use the background fill color/pattern
1355             default: break;
1356         }
1357         rSet.Put( XFillStyleItem( eXFill ) );
1358 
1359         double dTrans  = 1.0;
1360         double dBackTrans = 1.0;
1361         if (IsProperty(DFF_Prop_fillOpacity))
1362         {
1363             dTrans = GetPropertyValue(DFF_Prop_fillOpacity, 0) / 65536.0;
1364             if ( eXFill != drawing::FillStyle_GRADIENT )
1365             {
1366                 dTrans = dTrans * 100;
1367                 rSet.Put(XFillTransparenceItem(
1368                     sal_uInt16(100 - ::rtl::math::round(dTrans))));
1369             }
1370         }
1371 
1372         if ( IsProperty(DFF_Prop_fillBackOpacity) )
1373             dBackTrans = GetPropertyValue(DFF_Prop_fillBackOpacity, 0) / 65536.0;
1374 
1375         if ( ( eMSO_FillType == mso_fillShadeCenter ) && ( eXFill == drawing::FillStyle_BITMAP ) )
1376         {
1377             ApplyRectangularGradientAsBitmap( rManager, rIn, rSet, aShadeColors, rObjData, mnFix16Angle );
1378         }
1379         else if ( eXFill == drawing::FillStyle_GRADIENT )
1380         {
1381             ImportGradientColor ( rSet, eMSO_FillType, dTrans , dBackTrans );
1382         }
1383         else if ( eXFill == drawing::FillStyle_BITMAP )
1384         {
1385             if( IsProperty( DFF_Prop_fillBlip ) )
1386             {
1387                 Graphic aGraf;
1388                 // first try to get BLIP from cache
1389                 bool bOK = const_cast<SvxMSDffManager&>(rManager).GetBLIP( GetPropertyValue( DFF_Prop_fillBlip, 0 ), aGraf );
1390                 // then try directly from stream (i.e. Excel chart hatches/bitmaps)
1391                 if ( !bOK )
1392                     bOK = SeekToContent( DFF_Prop_fillBlip, rIn ) && SvxMSDffManager::GetBLIPDirect( rIn, aGraf );
1393                 if ( bOK )
1394                 {
1395                     if ( eMSO_FillType == mso_fillPattern )
1396                     {
1397                         Bitmap aBmp( aGraf.GetBitmapEx().GetBitmap() );
1398                         if( aBmp.GetSizePixel().Width() == 8 && aBmp.GetSizePixel().Height() == 8 && aBmp.GetColorCount() == 2)
1399                         {
1400                             Color aCol1( COL_WHITE ), aCol2( COL_WHITE );
1401 
1402                             if ( IsProperty( DFF_Prop_fillColor ) )
1403                                 aCol1 = rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillColor, 0 ), DFF_Prop_fillColor );
1404 
1405                             if ( IsProperty( DFF_Prop_fillBackColor ) )
1406                                 aCol2 = rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillBackColor, 0 ), DFF_Prop_fillBackColor );
1407 
1408                             // Create a bitmap for the pattern with expected colors
1409                             vcl::bitmap::RawBitmap aResult(Size(8, 8), 24);
1410                             {
1411                                 Bitmap::ScopedReadAccess pRead(aBmp);
1412 
1413                                 for (tools::Long y = 0; y < aResult.Height(); ++y)
1414                                 {
1415                                     Scanline pScanlineRead = pRead->GetScanline( y );
1416                                     for (tools::Long x = 0; x < aResult.Width(); ++x)
1417                                     {
1418                                         Color aReadColor;
1419                                         if (pRead->HasPalette())
1420                                             aReadColor = pRead->GetPaletteColor(pRead->GetIndexFromData(pScanlineRead, x));
1421                                         else
1422                                             aReadColor = pRead->GetPixelFromData(pScanlineRead, x);
1423 
1424                                         if (aReadColor == Color(0))
1425                                             aResult.SetPixel(y, x, aCol2);
1426                                         else
1427                                             aResult.SetPixel(y, x, aCol1);
1428                                     }
1429                                 }
1430                             }
1431                             aGraf = Graphic(vcl::bitmap::CreateFromData(std::move(aResult)));
1432                         }
1433 
1434                         rSet.Put(XFillBitmapItem(OUString(), aGraf));
1435                     }
1436                     else if ( eMSO_FillType == mso_fillTexture )
1437                     {
1438                         rSet.Put(XFillBmpTileItem(true));
1439                         rSet.Put(XFillBitmapItem(OUString(), aGraf));
1440                         rSet.Put(XFillBmpSizeXItem(GetPropertyValue(DFF_Prop_fillWidth, 0) / 360));
1441                         rSet.Put(XFillBmpSizeYItem(GetPropertyValue(DFF_Prop_fillHeight, 0) / 360));
1442                         rSet.Put(XFillBmpSizeLogItem(true));
1443                     }
1444                     else
1445                     {
1446                         rSet.Put(XFillBitmapItem(OUString(), aGraf));
1447                         rSet.Put(XFillBmpTileItem(false));
1448                     }
1449                 }
1450             }
1451         }
1452     }
1453     else
1454         rSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
1455 }
1456 
1457 void DffPropertyReader::ApplyCustomShapeTextAttributes( SfxItemSet& rSet ) const
1458 {
1459     bool  bVerticalText = false;
1460     sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 25 * 3600 ) / 360;     // 0.25 cm (emu)
1461     sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 25 * 3600 ) / 360;   // 0.25 cm (emu)
1462     sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 13 * 3600 ) / 360;       // 0.13 cm (emu)
1463     sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 13 * 3600 ) /360;  // 0.13 cm (emu)
1464 
1465     SdrTextVertAdjust eTVA;
1466     SdrTextHorzAdjust eTHA;
1467 
1468     if ( IsProperty( DFF_Prop_txflTextFlow ) )
1469     {
1470         auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF;
1471         switch( eTextFlow )
1472         {
1473             case mso_txflTtoBA :    /* #68110# */   // Top to Bottom @-font, oben -> unten
1474             case mso_txflTtoBN :                    // Top to Bottom non-@, oben -> unten
1475             case mso_txflVertN :                    // Vertical, non-@, oben -> unten
1476                 bVerticalText = true;           // nTextRotationAngle += 27000;
1477             break;
1478             default: break;
1479         }
1480     }
1481     sal_Int32 nFontDirection = GetPropertyValue( DFF_Prop_cdirFont, mso_cdir0 );
1482     if ( ( nFontDirection == 1 ) || ( nFontDirection == 3 ) )
1483         bVerticalText = !bVerticalText;
1484 
1485     if ( bVerticalText )
1486     {
1487         eTHA = SDRTEXTHORZADJUST_CENTER;
1488 
1489         // read text anchor
1490         sal_uInt32 eTextAnchor = GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop );
1491 
1492         switch( eTextAnchor )
1493         {
1494             case mso_anchorTop:
1495             case mso_anchorTopCentered:
1496             case mso_anchorTopBaseline:
1497             case mso_anchorTopCenteredBaseline:
1498                 eTHA = SDRTEXTHORZADJUST_RIGHT;
1499             break;
1500 
1501             case mso_anchorMiddle :
1502             case mso_anchorMiddleCentered:
1503                 eTHA = SDRTEXTHORZADJUST_CENTER;
1504             break;
1505 
1506             case mso_anchorBottom:
1507             case mso_anchorBottomCentered:
1508             case mso_anchorBottomBaseline:
1509             case mso_anchorBottomCenteredBaseline:
1510                 eTHA = SDRTEXTHORZADJUST_LEFT;
1511             break;
1512         }
1513         // if there is a 100% use of following attributes, the textbox can been aligned also in vertical direction
1514         switch ( eTextAnchor )
1515         {
1516             case mso_anchorTopCentered :
1517             case mso_anchorMiddleCentered :
1518             case mso_anchorBottomCentered :
1519             case mso_anchorTopCenteredBaseline:
1520             case mso_anchorBottomCenteredBaseline:
1521                 eTVA = SDRTEXTVERTADJUST_CENTER;
1522             break;
1523 
1524             default :
1525                 eTVA = SDRTEXTVERTADJUST_TOP;
1526             break;
1527         }
1528     }
1529     else
1530     {
1531         eTVA = SDRTEXTVERTADJUST_CENTER;
1532 
1533         // read text anchor
1534         sal_uInt32 eTextAnchor = GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop );
1535 
1536         switch( eTextAnchor )
1537         {
1538             case mso_anchorTop:
1539             case mso_anchorTopCentered:
1540             case mso_anchorTopBaseline:
1541             case mso_anchorTopCenteredBaseline:
1542                 eTVA = SDRTEXTVERTADJUST_TOP;
1543             break;
1544 
1545             case mso_anchorMiddle :
1546             case mso_anchorMiddleCentered:
1547                 eTVA = SDRTEXTVERTADJUST_CENTER;
1548             break;
1549 
1550             case mso_anchorBottom:
1551             case mso_anchorBottomCentered:
1552             case mso_anchorBottomBaseline:
1553             case mso_anchorBottomCenteredBaseline:
1554                 eTVA = SDRTEXTVERTADJUST_BOTTOM;
1555             break;
1556         }
1557         // if there is a 100% usage of following attributes, the textbox can be aligned also in horizontal direction
1558         switch ( eTextAnchor )
1559         {
1560             case mso_anchorTopCentered :
1561             case mso_anchorMiddleCentered :
1562             case mso_anchorBottomCentered :
1563             case mso_anchorTopCenteredBaseline:
1564             case mso_anchorBottomCenteredBaseline:
1565                 eTHA = SDRTEXTHORZADJUST_CENTER;    // the text has to be displayed using the full width;
1566             break;
1567 
1568             default :
1569                 eTHA = SDRTEXTHORZADJUST_LEFT;
1570             break;
1571         }
1572     }
1573     rSet.Put( SvxFrameDirectionItem( bVerticalText ? SvxFrameDirection::Vertical_RL_TB : SvxFrameDirection::Horizontal_LR_TB, EE_PARA_WRITINGDIR ) );
1574 
1575     rSet.Put( SdrTextVertAdjustItem( eTVA ) );
1576     rSet.Put( SdrTextHorzAdjustItem( eTHA ) );
1577 
1578     rSet.Put( makeSdrTextLeftDistItem( nTextLeft ) );
1579     rSet.Put( makeSdrTextRightDistItem( nTextRight ) );
1580     rSet.Put( makeSdrTextUpperDistItem( nTextTop ) );
1581     rSet.Put( makeSdrTextLowerDistItem( nTextBottom ) );
1582 
1583     rSet.Put( makeSdrTextWordWrapItem( GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare) != mso_wrapNone ) );
1584     rSet.Put( makeSdrTextAutoGrowHeightItem( ( GetPropertyValue( DFF_Prop_FitTextToShape, 0 ) & 2 ) != 0 ) );
1585 }
1586 
1587 void DffPropertyReader::ApplyCustomShapeGeometryAttributes( SvStream& rIn, SfxItemSet& rSet, const DffObjData& rObjData ) const
1588 {
1589 
1590     sal_uInt32 nAdjustmentsWhichNeedsToBeConverted = 0;
1591 
1592 
1593     // creating SdrCustomShapeGeometryItem
1594 
1595     typedef std::vector< beans::PropertyValue > PropVec;
1596 
1597     // aPropVec will be filled with all PropertyValues
1598     PropVec aPropVec;
1599     PropertyValue aProp;
1600 
1601 
1602     // "Type" property, including the predefined CustomShape type name
1603 
1604     aProp.Name  = "Type";
1605     aProp.Value <<= EnhancedCustomShapeTypeNames::Get( rObjData.eShapeType );
1606     aPropVec.push_back( aProp );
1607 
1608 
1609     // "ViewBox"
1610 
1611 
1612     sal_Int32 nCoordWidth = 21600;  // needed to replace handle type center with absolute value
1613     sal_Int32 nCoordHeight= 21600;
1614     if ( IsProperty( DFF_Prop_geoLeft ) || IsProperty( DFF_Prop_geoTop ) || IsProperty( DFF_Prop_geoRight ) || IsProperty( DFF_Prop_geoBottom ) )
1615     {
1616         css::awt::Rectangle aViewBox;
1617         aViewBox.X = GetPropertyValue( DFF_Prop_geoLeft, 0 );
1618         aViewBox.Y = GetPropertyValue( DFF_Prop_geoTop, 0 );
1619         aViewBox.Width = nCoordWidth = o3tl::saturating_sub<sal_Int32>(GetPropertyValue(DFF_Prop_geoRight, 21600), aViewBox.X);
1620         aViewBox.Height = nCoordHeight = o3tl::saturating_sub<sal_Int32>(GetPropertyValue(DFF_Prop_geoBottom, 21600), aViewBox.Y);
1621         aProp.Name = "ViewBox";
1622         aProp.Value <<= aViewBox;
1623         aPropVec.push_back( aProp );
1624     }
1625 
1626     // TextRotateAngle
1627 
1628     if ( IsProperty( DFF_Prop_txflTextFlow ) || IsProperty( DFF_Prop_cdirFont ) )
1629     {
1630         sal_Int32 nTextRotateAngle = 0;
1631         auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF;
1632 
1633         if ( eTextFlow == mso_txflBtoT )    // Bottom to Top non-@
1634             nTextRotateAngle += 90;
1635         switch( GetPropertyValue( DFF_Prop_cdirFont, mso_cdir0 ) )  // SJ: mso_cdir90 and mso_cdir270 will be simulated by
1636         {                                                           // activating vertical writing for the text objects
1637             case mso_cdir90 :
1638             {
1639                 if ( eTextFlow == mso_txflTtoBA )
1640                     nTextRotateAngle -= 180;
1641             }
1642             break;
1643             case mso_cdir180: nTextRotateAngle -= 180; break;
1644             case mso_cdir270:
1645             {
1646                 if ( eTextFlow != mso_txflTtoBA )
1647                     nTextRotateAngle -= 180;
1648             }
1649             break;
1650             default: break;
1651         }
1652         if ( nTextRotateAngle )
1653         {
1654             double fTextRotateAngle = nTextRotateAngle;
1655             aProp.Name = "TextRotateAngle";
1656             aProp.Value <<= fTextRotateAngle;
1657             aPropVec.push_back( aProp );
1658         }
1659     }
1660 
1661     // "Extrusion" PropertySequence element
1662 
1663     bool bExtrusionOn = ( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 8 ) != 0;
1664     if ( bExtrusionOn )
1665     {
1666         PropVec aExtrusionPropVec;
1667 
1668         // "Extrusion"
1669         aProp.Name = "Extrusion";
1670         aProp.Value <<= bExtrusionOn;
1671         aExtrusionPropVec.push_back( aProp );
1672 
1673         // "Brightness"
1674         if ( IsProperty( DFF_Prop_c3DAmbientIntensity ) )
1675         {
1676             double fBrightness = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DAmbientIntensity, 0 ));
1677             fBrightness /= 655.36;
1678             aProp.Name = "Brightness";
1679             aProp.Value <<= fBrightness;
1680             aExtrusionPropVec.push_back( aProp );
1681         }
1682         // "Depth" in 1/100mm
1683         if ( IsProperty( DFF_Prop_c3DExtrudeBackward ) || IsProperty( DFF_Prop_c3DExtrudeForward ) )
1684         {
1685             double fBackDepth = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DExtrudeBackward, 1270 * 360 ))) / 360.0;
1686             double fForeDepth = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DExtrudeForward, 0 ))) / 360.0;
1687             double fDepth = fBackDepth + fForeDepth;
1688             double fFraction = fDepth != 0.0 ? fForeDepth / fDepth : 0;
1689             EnhancedCustomShapeParameterPair aDepthParaPair;
1690             aDepthParaPair.First.Value <<= fDepth;
1691             aDepthParaPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
1692             aDepthParaPair.Second.Value <<= fFraction;
1693             aDepthParaPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
1694             aProp.Name = "Depth";
1695             aProp.Value <<= aDepthParaPair;
1696             aExtrusionPropVec.push_back( aProp );
1697         }
1698         // "Diffusion"
1699         if ( IsProperty( DFF_Prop_c3DDiffuseAmt ) )
1700         {
1701             double fDiffusion = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DDiffuseAmt, 0 ));
1702             fDiffusion /= 655.36;
1703             aProp.Name = "Diffusion";
1704             aProp.Value <<= fDiffusion;
1705             aExtrusionPropVec.push_back( aProp );
1706         }
1707         // "NumberOfLineSegments"
1708         if ( IsProperty( DFF_Prop_c3DTolerance ) )
1709         {
1710             aProp.Name = "NumberOfLineSegments";
1711             aProp.Value <<= static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DTolerance, 0 ));
1712             aExtrusionPropVec.push_back( aProp );
1713         }
1714         // "LightFace"
1715         bool bExtrusionLightFace = ( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 1 ) != 0;
1716         aProp.Name = "LightFace";
1717         aProp.Value <<= bExtrusionLightFace;
1718         aExtrusionPropVec.push_back( aProp );
1719         // "FirstLightHarsh"
1720         bool bExtrusionFirstLightHarsh = ( GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 2 ) != 0;
1721         aProp.Name = "FirstLightHarsh";
1722         aProp.Value <<= bExtrusionFirstLightHarsh;
1723         aExtrusionPropVec.push_back( aProp );
1724         // "SecondLightHarsh"
1725         bool bExtrusionSecondLightHarsh = ( GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 1 ) != 0;
1726         aProp.Name = "SecondLightHarsh";
1727         aProp.Value <<= bExtrusionSecondLightHarsh;
1728         aExtrusionPropVec.push_back( aProp );
1729         // "FirstLightLevel"
1730         if ( IsProperty( DFF_Prop_c3DKeyIntensity ) )
1731         {
1732             double fFirstLightLevel = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DKeyIntensity, 0 ));
1733             fFirstLightLevel /= 655.36;
1734             aProp.Name = "FirstLightLevel";
1735             aProp.Value <<= fFirstLightLevel;
1736             aExtrusionPropVec.push_back( aProp );
1737         }
1738         // "SecondLightLevel"
1739         if ( IsProperty( DFF_Prop_c3DFillIntensity ) )
1740         {
1741             double fSecondLightLevel = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DFillIntensity, 0 ));
1742             fSecondLightLevel /= 655.36;
1743             aProp.Name = "SecondLightLevel";
1744             aProp.Value <<= fSecondLightLevel;
1745             aExtrusionPropVec.push_back( aProp );
1746         }
1747         // "FirstLightDirection"
1748         if ( IsProperty( DFF_Prop_c3DKeyX ) || IsProperty( DFF_Prop_c3DKeyY ) || IsProperty( DFF_Prop_c3DKeyZ ) )
1749         {
1750             double fLightX = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DKeyX, 50000 )));
1751             double fLightY = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DKeyY, 0 )));
1752             double fLightZ = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DKeyZ, 10000 )));
1753             css::drawing::Direction3D aExtrusionFirstLightDirection( fLightX, fLightY, fLightZ );
1754             aProp.Name = "FirstLightDirection";
1755             aProp.Value <<= aExtrusionFirstLightDirection;
1756             aExtrusionPropVec.push_back( aProp );
1757         }
1758         // "SecondLightDirection"
1759         if ( IsProperty( DFF_Prop_c3DFillX ) || IsProperty( DFF_Prop_c3DFillY ) || IsProperty( DFF_Prop_c3DFillZ ) )
1760         {
1761             double fLight2X = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DFillX, sal_uInt32(-50000) )));
1762             double fLight2Y = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DFillY, 0 )));
1763             double fLight2Z = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DFillZ, 10000 )));
1764             css::drawing::Direction3D aExtrusionSecondLightDirection( fLight2X, fLight2Y, fLight2Z );
1765             aProp.Name = "SecondLightDirection";
1766             aProp.Value <<= aExtrusionSecondLightDirection;
1767             aExtrusionPropVec.push_back( aProp );
1768         }
1769 
1770         // "Metal"
1771         bool bExtrusionMetal = ( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 4 ) != 0;
1772         aProp.Name = "Metal";
1773         aProp.Value <<= bExtrusionMetal;
1774         aExtrusionPropVec.push_back( aProp );
1775         // "ShadeMode"
1776         if ( IsProperty( DFF_Prop_c3DRenderMode ) )
1777         {
1778             sal_uInt32 nExtrusionRenderMode = GetPropertyValue( DFF_Prop_c3DRenderMode, 0 );
1779             css::drawing::ShadeMode eExtrusionShadeMode( css::drawing::ShadeMode_FLAT );
1780             if ( nExtrusionRenderMode == mso_Wireframe )
1781                 eExtrusionShadeMode = css::drawing::ShadeMode_DRAFT;
1782 
1783             aProp.Name = "ShadeMode";
1784             aProp.Value <<= eExtrusionShadeMode;
1785             aExtrusionPropVec.push_back( aProp );
1786         }
1787         // "RotateAngle" in Grad
1788         if ( IsProperty( DFF_Prop_c3DXRotationAngle ) || IsProperty( DFF_Prop_c3DYRotationAngle ) )
1789         {
1790             double fAngleX = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DXRotationAngle, 0 ))) / 65536.0;
1791             double fAngleY = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DYRotationAngle, 0 ))) / 65536.0;
1792             EnhancedCustomShapeParameterPair aRotateAnglePair;
1793             aRotateAnglePair.First.Value <<= fAngleX;
1794             aRotateAnglePair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
1795             aRotateAnglePair.Second.Value <<= fAngleY;
1796             aRotateAnglePair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
1797             aProp.Name = "RotateAngle";
1798             aProp.Value <<= aRotateAnglePair;
1799             aExtrusionPropVec.push_back( aProp );
1800         }
1801 
1802         // "AutoRotationCenter"
1803         if ( ( GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 8 ) == 0 )
1804         {
1805             // "RotationCenter"
1806             if ( IsProperty( DFF_Prop_c3DRotationCenterX ) || IsProperty( DFF_Prop_c3DRotationCenterY ) || IsProperty( DFF_Prop_c3DRotationCenterZ ) )
1807             {
1808                 css::drawing::Direction3D aRotationCenter(
1809                     static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DRotationCenterX, 0 ))) / 360.0,
1810                     static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DRotationCenterY, 0 ))) / 360.0,
1811                     static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DRotationCenterZ, 0 ))) / 360.0 );
1812 
1813                 aProp.Name = "RotationCenter";
1814                 aProp.Value <<= aRotationCenter;
1815                 aExtrusionPropVec.push_back( aProp );
1816             }
1817         }
1818         // "Shininess"
1819         if ( IsProperty( DFF_Prop_c3DShininess ) )
1820         {
1821             double fShininess = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DShininess, 0 ));
1822             fShininess /= 655.36;
1823             aProp.Name = "Shininess";
1824             aProp.Value <<= fShininess;
1825             aExtrusionPropVec.push_back( aProp );
1826         }
1827         // "Skew"
1828         if ( IsProperty( DFF_Prop_c3DSkewAmount ) || IsProperty( DFF_Prop_c3DSkewAngle ) )
1829         {
1830             double fSkewAmount = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DSkewAmount, 50 ));
1831             double fSkewAngle = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DSkewAngle, sal::static_int_cast< sal_uInt32 >(-135 * 65536) ))) / 65536.0;
1832 
1833             EnhancedCustomShapeParameterPair aSkewPair;
1834             aSkewPair.First.Value <<= fSkewAmount;
1835             aSkewPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
1836             aSkewPair.Second.Value <<= fSkewAngle;
1837             aSkewPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
1838             aProp.Name = "Skew";
1839             aProp.Value <<= aSkewPair;
1840             aExtrusionPropVec.push_back( aProp );
1841         }
1842         // "Specularity"
1843         if ( IsProperty( DFF_Prop_c3DSpecularAmt ) )
1844         {
1845             double fSpecularity = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DSpecularAmt, 0 ));
1846             fSpecularity /= 1333;
1847             aProp.Name = "Specularity";
1848             aProp.Value <<= fSpecularity;
1849             aExtrusionPropVec.push_back( aProp );
1850         }
1851         // "ProjectionMode"
1852         ProjectionMode eProjectionMode = (GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 4) ? ProjectionMode_PARALLEL : ProjectionMode_PERSPECTIVE;
1853         aProp.Name = "ProjectionMode";
1854         aProp.Value <<= eProjectionMode;
1855         aExtrusionPropVec.push_back( aProp );
1856 
1857         // "ViewPoint" in 1/100mm
1858         if ( IsProperty( DFF_Prop_c3DXViewpoint ) || IsProperty( DFF_Prop_c3DYViewpoint ) || IsProperty( DFF_Prop_c3DZViewpoint ) )
1859         {
1860             double fViewX = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DXViewpoint, 1250000 ))) / 360.0;
1861             double fViewY = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DYViewpoint, sal_uInt32(-1250000) )))/ 360.0;
1862             double fViewZ = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DZViewpoint, 9000000 ))) / 360.0;
1863             css::drawing::Position3D aExtrusionViewPoint( fViewX, fViewY, fViewZ );
1864             aProp.Name = "ViewPoint";
1865             aProp.Value <<= aExtrusionViewPoint;
1866             aExtrusionPropVec.push_back( aProp );
1867         }
1868         // "Origin"
1869         if ( IsProperty( DFF_Prop_c3DOriginX ) || IsProperty( DFF_Prop_c3DOriginY ) )
1870         {
1871             double fOriginX = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DOriginX, 32768 )));
1872             double fOriginY = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DOriginY, sal_uInt32(-32768) )));
1873             fOriginX /= 65536;
1874             fOriginY /= 65536;
1875             EnhancedCustomShapeParameterPair aOriginPair;
1876             aOriginPair.First.Value <<= fOriginX;
1877             aOriginPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
1878             aOriginPair.Second.Value <<= fOriginY;
1879             aOriginPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
1880             aProp.Name = "Origin";
1881             aProp.Value <<= aOriginPair;
1882             aExtrusionPropVec.push_back( aProp );
1883         }
1884         // "ExtrusionColor"
1885         bool bExtrusionColor = IsProperty( DFF_Prop_c3DExtrusionColor );    // ( GetPropertyValue( DFF_Prop_fc3DLightFace ) & 2 ) != 0;
1886         aProp.Name = "Color";
1887         aProp.Value <<= bExtrusionColor;
1888         aExtrusionPropVec.push_back( aProp );
1889         if ( IsProperty( DFF_Prop_c3DExtrusionColor ) )
1890             rSet.Put( XSecondaryFillColorItem( OUString(), rManager.MSO_CLR_ToColor(
1891                 GetPropertyValue( DFF_Prop_c3DExtrusionColor, 0 ), DFF_Prop_c3DExtrusionColor ) ) );
1892         // pushing the whole Extrusion element
1893         aProp.Name = "Extrusion";
1894         aProp.Value <<= comphelper::containerToSequence(aExtrusionPropVec);
1895         aPropVec.push_back( aProp );
1896     }
1897 
1898 
1899     // "Equations" PropertySequence element
1900 
1901     if ( IsProperty( DFF_Prop_pFormulas ) )
1902     {
1903         sal_uInt16 nNumElem = 0;
1904 
1905         if ( SeekToContent( DFF_Prop_pFormulas, rIn ) )
1906         {
1907             sal_uInt16 nNumElemMem = 0;
1908             sal_uInt16 nElemSize = 8;
1909             rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemMem ).ReadUInt16( nElemSize );
1910         }
1911         if ( nNumElem <= 128 )
1912         {
1913             uno::Sequence< OUString > aEquations( nNumElem );
1914             for ( sal_uInt16 i = 0; i < nNumElem; i++ )
1915             {
1916                 sal_Int16 nP1(0), nP2(0), nP3(0);
1917                 sal_uInt16 nFlags(0);
1918                 rIn.ReadUInt16( nFlags ).ReadInt16( nP1 ).ReadInt16( nP2 ).ReadInt16( nP3 );
1919                 aEquations[ i ] = EnhancedCustomShape2d::GetEquation( nFlags, nP1, nP2, nP3 );
1920             }
1921             // pushing the whole Equations element
1922             aProp.Name = "Equations";
1923             aProp.Value <<= aEquations;
1924             aPropVec.push_back( aProp );
1925         }
1926     }
1927 
1928 
1929     // "Handles" PropertySequence element
1930 
1931     if ( IsProperty( DFF_Prop_Handles ) )
1932     {
1933         sal_uInt16 nNumElem = 0;
1934         sal_uInt16 nElemSize = 36;
1935 
1936         if ( SeekToContent( DFF_Prop_Handles, rIn ) )
1937         {
1938             sal_uInt16 nNumElemMem = 0;
1939             rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemMem ).ReadUInt16( nElemSize );
1940         }
1941         bool bImport = false;
1942         if (nElemSize == 36)
1943         {
1944             //sanity check that the stream is long enough to fulfill nNumElem * nElemSize;
1945             bImport = rIn.remainingSize() / nElemSize >= nNumElem;
1946         }
1947         if (bImport)
1948         {
1949             uno::Sequence< beans::PropertyValues > aHandles( nNumElem );
1950             for (sal_uInt32 i = 0; i < nNumElem; ++i)
1951             {
1952                 PropVec aHandlePropVec;
1953                 sal_uInt32 nFlagsTmp(0);
1954                 sal_Int32  nPositionX(0), nPositionY(0), nCenterX(0), nCenterY(0), nRangeXMin(0), nRangeXMax(0), nRangeYMin(0), nRangeYMax(0);
1955                 rIn.ReadUInt32( nFlagsTmp )
1956                    .ReadInt32( nPositionX )
1957                    .ReadInt32( nPositionY )
1958                    .ReadInt32( nCenterX )
1959                    .ReadInt32( nCenterY )
1960                    .ReadInt32( nRangeXMin )
1961                    .ReadInt32( nRangeXMax )
1962                    .ReadInt32( nRangeYMin )
1963                    .ReadInt32( nRangeYMax );
1964                 SvxMSDffHandleFlags nFlags = static_cast<SvxMSDffHandleFlags>(nFlagsTmp);
1965                 if ( nPositionX == 2 )  // replacing center position with absolute value
1966                     nPositionX = nCoordWidth / 2;
1967                 if ( nPositionY == 2 )
1968                     nPositionY = nCoordHeight / 2;
1969                 EnhancedCustomShapeParameterPair aPosition;
1970                 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.First,  nPositionX, true, true  );
1971                 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.Second, nPositionY, true, false );
1972                 aProp.Name = "Position";
1973                 aProp.Value <<= aPosition;
1974                 aHandlePropVec.push_back( aProp );
1975 
1976                 if ( nFlags & SvxMSDffHandleFlags::MIRRORED_X )
1977                 {
1978                     aProp.Name = "MirroredX";
1979                     aProp.Value <<= true;
1980                     aHandlePropVec.push_back( aProp );
1981                 }
1982                 if ( nFlags & SvxMSDffHandleFlags::MIRRORED_Y )
1983                 {
1984                     aProp.Name = "MirroredY";
1985                     aProp.Value <<= true;
1986                     aHandlePropVec.push_back( aProp );
1987                 }
1988                 if ( nFlags & SvxMSDffHandleFlags::SWITCHED )
1989                 {
1990                     aProp.Name = "Switched";
1991                     aProp.Value <<= true;
1992                     aHandlePropVec.push_back( aProp );
1993                 }
1994                 if ( nFlags & SvxMSDffHandleFlags::POLAR )
1995                 {
1996                     if ( nCenterX == 2 )
1997                         nCenterX = nCoordWidth / 2;
1998                     if ( nCenterY == 2 )
1999                         nCenterY = nCoordHeight / 2;
2000                     if ((nPositionY >= 0x256 || nPositionY <= 0x107) && i < sizeof(sal_uInt32) * 8)   // position y
2001                         nAdjustmentsWhichNeedsToBeConverted |= ( 1U << i );
2002                     EnhancedCustomShapeParameterPair aPolar;
2003                     EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPolar.First,  nCenterX, bool( nFlags & SvxMSDffHandleFlags::CENTER_X_IS_SPECIAL ), true  );
2004                     EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPolar.Second, nCenterY, bool( nFlags & SvxMSDffHandleFlags::CENTER_Y_IS_SPECIAL ), false );
2005                     aProp.Name = "Polar";
2006                     aProp.Value <<= aPolar;
2007                     aHandlePropVec.push_back( aProp );
2008                 }
2009                 if ( nFlags & SvxMSDffHandleFlags::MAP )
2010                 {
2011                     if ( nCenterX == 2 )
2012                         nCenterX = nCoordWidth / 2;
2013                     if ( nCenterY == 2 )
2014                         nCenterY = nCoordHeight / 2;
2015                     EnhancedCustomShapeParameterPair aMap;
2016                     EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aMap.First,  nCenterX, bool( nFlags & SvxMSDffHandleFlags::CENTER_X_IS_SPECIAL ), true  );
2017                     EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aMap.Second, nCenterY, bool( nFlags & SvxMSDffHandleFlags::CENTER_Y_IS_SPECIAL ), false );
2018                     aProp.Name = "Map";
2019                     aProp.Value <<= aMap;
2020                     aHandlePropVec.push_back( aProp );
2021                 }
2022                 if ( nFlags & SvxMSDffHandleFlags::RANGE )
2023                 {
2024                     if ( static_cast<sal_uInt32>(nRangeXMin) != 0x80000000 )
2025                     {
2026                         if ( nRangeXMin == 2 )
2027                             nRangeXMin = nCoordWidth / 2;
2028                         EnhancedCustomShapeParameter aRangeXMinimum;
2029                         EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMinimum,  nRangeXMin,
2030                             bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL ), true  );
2031                         aProp.Name = "RangeXMinimum";
2032                         aProp.Value <<= aRangeXMinimum;
2033                         aHandlePropVec.push_back( aProp );
2034                     }
2035                     if ( static_cast<sal_uInt32>(nRangeXMax) != 0x7fffffff )
2036                     {
2037                         if ( nRangeXMax == 2 )
2038                             nRangeXMax = nCoordWidth / 2;
2039                         EnhancedCustomShapeParameter aRangeXMaximum;
2040                         EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMaximum, nRangeXMax,
2041                             bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL ), false );
2042                         aProp.Name = "RangeXMaximum";
2043                         aProp.Value <<= aRangeXMaximum;
2044                         aHandlePropVec.push_back( aProp );
2045                     }
2046                     if ( static_cast<sal_uInt32>(nRangeYMin) != 0x80000000 )
2047                     {
2048                         if ( nRangeYMin == 2 )
2049                             nRangeYMin = nCoordHeight / 2;
2050                         EnhancedCustomShapeParameter aRangeYMinimum;
2051                         EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMinimum, nRangeYMin,
2052                             bool( nFlags & SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL ), true );
2053                         aProp.Name = "RangeYMinimum";
2054                         aProp.Value <<= aRangeYMinimum;
2055                         aHandlePropVec.push_back( aProp );
2056                     }
2057                     if ( static_cast<sal_uInt32>(nRangeYMax) != 0x7fffffff )
2058                     {
2059                         if ( nRangeYMax == 2 )
2060                             nRangeYMax = nCoordHeight / 2;
2061                         EnhancedCustomShapeParameter aRangeYMaximum;
2062                         EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMaximum, nRangeYMax,
2063                             bool( nFlags & SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL ), false );
2064                         aProp.Name = "RangeYMaximum";
2065                         aProp.Value <<= aRangeYMaximum;
2066                         aHandlePropVec.push_back( aProp );
2067                     }
2068                 }
2069                 if ( nFlags & SvxMSDffHandleFlags::RADIUS_RANGE )
2070                 {
2071                     if ( static_cast<sal_uInt32>(nRangeXMin) != 0x7fffffff )
2072                     {
2073                         if ( nRangeXMin == 2 )
2074                             nRangeXMin = nCoordWidth / 2;
2075                         EnhancedCustomShapeParameter aRadiusRangeMinimum;
2076                         EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMinimum, nRangeXMin,
2077                             bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL ), true  );
2078                         aProp.Name = "RadiusRangeMinimum";
2079                         aProp.Value <<= aRadiusRangeMinimum;
2080                         aHandlePropVec.push_back( aProp );
2081                     }
2082                     if ( static_cast<sal_uInt32>(nRangeXMax) != 0x80000000 )
2083                     {
2084                         if ( nRangeXMax == 2 )
2085                             nRangeXMax = nCoordWidth / 2;
2086                         EnhancedCustomShapeParameter aRadiusRangeMaximum;
2087                         EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMaximum, nRangeXMax,
2088                             bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL ), false );
2089                         aProp.Name = "RadiusRangeMaximum";
2090                         aProp.Value <<= aRadiusRangeMaximum;
2091                         aHandlePropVec.push_back( aProp );
2092                     }
2093                 }
2094                 if ( !aHandlePropVec.empty() )
2095                 {
2096                     aHandles[ i ] = comphelper::containerToSequence(aHandlePropVec);
2097                 }
2098             }
2099             // pushing the whole Handles element
2100             aProp.Name = "Handles";
2101             aProp.Value <<= aHandles;
2102             aPropVec.push_back( aProp );
2103         }
2104     }
2105     else
2106     {
2107         const mso_CustomShape* pDefCustomShape = GetCustomShapeContent( rObjData.eShapeType );
2108         if ( pDefCustomShape && pDefCustomShape->nHandles && pDefCustomShape->pHandles )
2109         {
2110             sal_uInt32 i, nCnt = pDefCustomShape->nHandles;
2111             const SvxMSDffHandle* pData = pDefCustomShape->pHandles;
2112             for ( i = 0; i < nCnt; i++, pData++ )
2113             {
2114                 if ( pData->nFlags & SvxMSDffHandleFlags::POLAR )
2115                 {
2116                     if ( ( pData->nPositionY >= 0x256 ) || ( pData->nPositionY <= 0x107 ) )
2117                         nAdjustmentsWhichNeedsToBeConverted |= ( 1U << i );
2118                 }
2119             }
2120         }
2121     }
2122 
2123     // "Path" PropertySequence element
2124 
2125     {
2126         PropVec aPathPropVec;
2127 
2128         // "Path/ExtrusionAllowed"
2129         if ( IsHardAttribute( DFF_Prop_f3DOK ) )
2130         {
2131             bool bExtrusionAllowed = ( GetPropertyValue( DFF_Prop_fFillOK, 0 ) & 16 ) != 0;
2132             aProp.Name = "ExtrusionAllowed";
2133             aProp.Value <<= bExtrusionAllowed;
2134             aPathPropVec.push_back( aProp );
2135         }
2136         // "Path/ConcentricGradientFillAllowed"
2137         if ( IsHardAttribute( DFF_Prop_fFillShadeShapeOK ) )
2138         {
2139             bool bConcentricGradientFillAllowed = ( GetPropertyValue( DFF_Prop_fFillOK, 0 ) & 2 ) != 0;
2140             aProp.Name = "ConcentricGradientFillAllowed";
2141             aProp.Value <<= bConcentricGradientFillAllowed;
2142             aPathPropVec.push_back( aProp );
2143         }
2144         // "Path/TextPathAllowed"
2145         if ( IsHardAttribute( DFF_Prop_fGtextOK ) || ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x4000 ) )
2146         {
2147             bool bTextPathAllowed = ( GetPropertyValue( DFF_Prop_fFillOK, 0 ) & 4 ) != 0;
2148             aProp.Name = "TextPathAllowed";
2149             aProp.Value <<= bTextPathAllowed;
2150             aPathPropVec.push_back( aProp );
2151         }
2152         // Path/Coordinates
2153         if ( IsProperty( DFF_Prop_pVertices ) )
2154         {
2155             css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aCoordinates;
2156             sal_uInt16 nNumElemVert = 0;
2157             sal_uInt16 nElemSizeVert = 8;
2158 
2159             if ( SeekToContent( DFF_Prop_pVertices, rIn ) )
2160             {
2161                 sal_uInt16 nNumElemMemVert = 0;
2162                 rIn.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert );
2163                 // If this value is 0xFFF0 then this record is an array of truncated 8 byte elements. Only the 4
2164                 // low-order bytes are recorded
2165                 if (nElemSizeVert == 0xFFF0)
2166                     nElemSizeVert = 4;
2167             }
2168             //sanity check that the stream is long enough to fulfill nNumElem * nElemSize;
2169             bool bImport = nElemSizeVert && (rIn.remainingSize() / nElemSizeVert >= nNumElemVert);
2170             if (bImport)
2171             {
2172                 aCoordinates.realloc( nNumElemVert );
2173                 for (sal_uInt16 i = 0; i < nNumElemVert; ++i)
2174                 {
2175                     sal_Int32 nX(0), nY(0);
2176 
2177                     if ( nElemSizeVert == 8 )
2178                     {
2179                         rIn.ReadInt32( nX )
2180                            .ReadInt32( nY );
2181                     }
2182                     else
2183                     {
2184                         // The mso-spt19 (arc) uses this. But it needs unsigned integer. I don't
2185                         // know if other shape types also need it. They can be added as necessary.
2186                         bool bNeedsUnsigned = rObjData.eShapeType == mso_sptArc;
2187                         if (bNeedsUnsigned)
2188                         {
2189                             sal_uInt16 nTmpA(0), nTmpB(0);
2190                             rIn.ReadUInt16(nTmpA)
2191                                .ReadUInt16(nTmpB);
2192                             nX = nTmpA;
2193                             nY = nTmpB;
2194                         }
2195                         else
2196                         {
2197                             sal_Int16 nTmpA(0), nTmpB(0);
2198                             rIn.ReadInt16( nTmpA )
2199                                .ReadInt16( nTmpB );
2200                             nX = nTmpA;
2201                             nY = nTmpB;
2202                         }
2203                     }
2204                     EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aCoordinates[ i ].First, nX );
2205                     EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aCoordinates[ i ].Second, nY );
2206                 }
2207             }
2208             aProp.Name = "Coordinates";
2209             aProp.Value <<= aCoordinates;
2210             aPathPropVec.push_back( aProp );
2211         }
2212         // Path/Segments
2213         if ( IsProperty( DFF_Prop_pSegmentInfo ) )
2214         {
2215             css::uno::Sequence< css::drawing::EnhancedCustomShapeSegment > aSegments;
2216 
2217             sal_uInt16 nNumElemSeg = 0;
2218 
2219             if ( SeekToContent( DFF_Prop_pSegmentInfo, rIn ) )
2220             {
2221                 sal_uInt16 nNumElemMemSeg = 0;
2222                 sal_uInt16 nElemSizeSeg = 2;
2223                 rIn.ReadUInt16( nNumElemSeg ).ReadUInt16( nNumElemMemSeg ).ReadUInt16( nElemSizeSeg );
2224             }
2225             sal_uInt64 nMaxEntriesPossible = rIn.remainingSize() / sizeof(sal_uInt16);
2226             if (nNumElemSeg > nMaxEntriesPossible)
2227             {
2228                 SAL_WARN("filter.ms", "NumElem list is longer than remaining bytes, ppt or parser is wrong");
2229                 nNumElemSeg = nMaxEntriesPossible;
2230             }
2231             if ( nNumElemSeg )
2232             {
2233                 aSegments.realloc( nNumElemSeg );
2234                 for (sal_uInt16 i = 0; i < nNumElemSeg; ++i)
2235                 {
2236                     sal_uInt16 nTmp(0);
2237                     rIn.ReadUInt16( nTmp );
2238                     sal_Int16 nCommand = EnhancedCustomShapeSegmentCommand::UNKNOWN;
2239                     sal_Int16 nCnt = static_cast<sal_Int16>( nTmp & 0x1fff );//Last 13 bits for segment points number
2240                     switch( nTmp >> 13 )//First 3 bits for command type
2241                     {
2242                         case 0x0:
2243                             nCommand = EnhancedCustomShapeSegmentCommand::LINETO;
2244                             if ( !nCnt ) nCnt = 1;
2245                             break;
2246                         case 0x1:
2247                             nCommand = EnhancedCustomShapeSegmentCommand::CURVETO;
2248                             if ( !nCnt ) nCnt = 1;
2249                             break;
2250                         case 0x2:
2251                             nCommand = EnhancedCustomShapeSegmentCommand::MOVETO;
2252                             if ( !nCnt ) nCnt = 1;
2253                             break;
2254                         case 0x3:
2255                             nCommand = EnhancedCustomShapeSegmentCommand::CLOSESUBPATH;
2256                             nCnt = 0;
2257                             break;
2258                         case 0x4:
2259                             nCommand = EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
2260                             nCnt = 0;
2261                             break;
2262                         case 0x5:
2263                         case 0x6:
2264                         {
2265                             switch ( ( nTmp >> 8 ) & 0x1f )//5 bits next to command type is for path escape type
2266                             {
2267                                 case 0x0:
2268                                 {
2269                                     //It is msopathEscapeExtension which is transformed into LINETO.
2270                                     //If issue happens, I think this part can be comment so that it will be taken as unknown command.
2271                                     //When export, origin data will be export without any change.
2272                                     nCommand = EnhancedCustomShapeSegmentCommand::LINETO;
2273                                     if ( !nCnt )
2274                                         nCnt = 1;
2275                                 }
2276                                 break;
2277                                 case 0x1:
2278                                 {
2279                                     nCommand = EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO;
2280                                     nCnt = ( nTmp & 0xff ) / 3;
2281                                 }
2282                                 break;
2283                                 case 0x2:
2284                                 {
2285                                     nCommand = EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE;
2286                                     nCnt = ( nTmp & 0xff ) / 3;
2287                                 }
2288                                 break;
2289                                 case 0x3:
2290                                 {
2291                                     nCommand = EnhancedCustomShapeSegmentCommand::ARCTO;
2292                                     nCnt = ( nTmp & 0xff ) >> 2;
2293                                 };
2294                                 break;
2295                                 case 0x4:
2296                                 {
2297                                     nCommand = EnhancedCustomShapeSegmentCommand::ARC;
2298                                     nCnt = ( nTmp & 0xff ) >> 2;
2299                                 }
2300                                 break;
2301                                 case 0x5:
2302                                 {
2303                                     nCommand = EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO;
2304                                     nCnt = ( nTmp & 0xff ) >> 2;
2305                                 }
2306                                 break;
2307                                 case 0x6:
2308                                 {
2309                                     nCommand = EnhancedCustomShapeSegmentCommand::CLOCKWISEARC;
2310                                     nCnt = ( nTmp & 0xff ) >> 2;
2311                                 }
2312                                 break;
2313                                 case 0x7:
2314                                 {
2315                                     nCommand = EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX;
2316                                     nCnt = nTmp & 0xff;
2317                                 }
2318                                 break;
2319                                 case 0x8:
2320                                 {
2321                                     nCommand = EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY;
2322                                     nCnt = nTmp & 0xff;
2323                                 }
2324                                 break;
2325                                 case 0xa: nCommand = EnhancedCustomShapeSegmentCommand::NOFILL; nCnt = 0; break;
2326                                 case 0xb: nCommand = EnhancedCustomShapeSegmentCommand::NOSTROKE; nCnt = 0; break;
2327                             }
2328                         }
2329                         break;
2330                     }
2331                     // if the command is unknown, we will store all the data in nCnt, so it will be possible to export without loss
2332                     if ( nCommand == EnhancedCustomShapeSegmentCommand::UNKNOWN )
2333                         nCnt = static_cast<sal_Int16>(nTmp);
2334                     aSegments[ i ].Command = nCommand;
2335                     aSegments[ i ].Count = nCnt;
2336                 }
2337             }
2338             aProp.Name = "Segments";
2339             aProp.Value <<= aSegments;
2340             aPathPropVec.push_back( aProp );
2341         }
2342         // Path/StretchX
2343         if ( IsProperty( DFF_Prop_stretchPointX ) )
2344         {
2345             sal_Int32 nStretchX = GetPropertyValue( DFF_Prop_stretchPointX, 0 );
2346             aProp.Name = "StretchX";
2347             aProp.Value <<= nStretchX;
2348             aPathPropVec.push_back( aProp );
2349         }
2350         // Path/StretchX
2351         if ( IsProperty( DFF_Prop_stretchPointY ) )
2352         {
2353             sal_Int32 nStretchY = GetPropertyValue( DFF_Prop_stretchPointY, 0 );
2354             aProp.Name = "StretchY";
2355             aProp.Value <<= nStretchY;
2356             aPathPropVec.push_back( aProp );
2357         }
2358         // Path/TextFrames
2359         if ( IsProperty( DFF_Prop_textRectangles ) )
2360         {
2361             sal_uInt16 nNumElem = 0;
2362             sal_uInt16 nElemSize = 16;
2363 
2364             if ( SeekToContent( DFF_Prop_textRectangles, rIn ) )
2365             {
2366                 sal_uInt16 nNumElemMem = 0;
2367                 rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemMem ).ReadUInt16( nElemSize );
2368             }
2369             bool bImport = false;
2370             if (nElemSize == 16)
2371             {
2372                 //sanity check that the stream is long enough to fulfill nNumElem * nElemSize;
2373                 bImport = rIn.remainingSize() / nElemSize >= nNumElem;
2374             }
2375             if (bImport)
2376             {
2377                 css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aTextFrames( nNumElem );
2378                 for (sal_uInt16 i = 0; i < nNumElem; ++i)
2379                 {
2380                     sal_Int32 nLeft(0), nTop(0), nRight(0), nBottom(0);
2381 
2382                     rIn.ReadInt32( nLeft )
2383                        .ReadInt32( nTop )
2384                        .ReadInt32( nRight )
2385                        .ReadInt32( nBottom );
2386 
2387                     EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aTextFrames[ i ].TopLeft.First,  nLeft );
2388                     EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aTextFrames[ i ].TopLeft.Second, nTop  );
2389                     EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aTextFrames[ i ].BottomRight.First,  nRight );
2390                     EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aTextFrames[ i ].BottomRight.Second, nBottom);
2391                 }
2392                 aProp.Name = "TextFrames";
2393                 aProp.Value <<= aTextFrames;
2394                 aPathPropVec.push_back( aProp );
2395             }
2396         }
2397         //Path/GluePoints
2398         if ( IsProperty( DFF_Prop_connectorPoints ) )
2399         {
2400             css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aGluePoints;
2401             sal_uInt16 nNumElemVert = 0;
2402             sal_uInt16 nElemSizeVert = 8;
2403 
2404             if ( SeekToContent( DFF_Prop_connectorPoints, rIn ) )
2405             {
2406                 sal_uInt16 nNumElemMemVert = 0;
2407                 rIn.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert );
2408                 // If this value is 0xFFF0 then this record is an array of truncated 8 byte elements. Only the 4
2409                 // low-order bytes are recorded
2410                 if (nElemSizeVert == 0xFFF0)
2411                     nElemSizeVert = 4;
2412             }
2413 
2414             // sanity check that the stream is long enough to fulfill nNumElemVert * nElemSizeVert;
2415             bool bImport = nElemSizeVert && (rIn.remainingSize() / nElemSizeVert >= nNumElemVert);
2416             if (bImport)
2417             {
2418                 aGluePoints.realloc( nNumElemVert );
2419                 for (sal_uInt16 i = 0; i < nNumElemVert; ++i)
2420                 {
2421                     sal_Int32 nX(0), nY(0);
2422                     if ( nElemSizeVert == 8 )
2423                     {
2424                         rIn.ReadInt32( nX )
2425                            .ReadInt32( nY );
2426                     }
2427                     else
2428                     {
2429                         sal_Int16 nTmpA(0), nTmpB(0);
2430 
2431                         rIn.ReadInt16( nTmpA )
2432                            .ReadInt16( nTmpB );
2433 
2434                         nX = nTmpA;
2435                         nY = nTmpB;
2436                     }
2437                     EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aGluePoints[ i ].First,  nX );
2438                     EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aGluePoints[ i ].Second, nY );
2439                 }
2440             }
2441             aProp.Name = "GluePoints";
2442             aProp.Value <<= aGluePoints;
2443             aPathPropVec.push_back( aProp );
2444         }
2445         if ( IsProperty( DFF_Prop_connectorType ) )
2446         {
2447             sal_Int16 nGluePointType = static_cast<sal_uInt16>(GetPropertyValue( DFF_Prop_connectorType, 0 ));
2448             aProp.Name = "GluePointType";
2449             aProp.Value <<= nGluePointType;
2450             aPathPropVec.push_back( aProp );
2451         }
2452         // pushing the whole Path element
2453         if ( !aPathPropVec.empty() )
2454         {
2455             aProp.Name = "Path";
2456             aProp.Value <<= comphelper::containerToSequence(aPathPropVec);
2457             aPropVec.push_back( aProp );
2458         }
2459     }
2460 
2461     // "TextPath" PropertySequence element
2462 
2463     bool bTextPathOn = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x4000 ) != 0;
2464     if ( bTextPathOn )
2465     {
2466         PropVec aTextPathPropVec;
2467 
2468         // TextPath
2469         aProp.Name = "TextPath";
2470         aProp.Value <<= bTextPathOn;
2471         aTextPathPropVec.push_back( aProp );
2472 
2473         // TextPathMode
2474         bool bTextPathFitPath = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x100 ) != 0;
2475 
2476         bool bTextPathFitShape;
2477         if ( IsHardAttribute( DFF_Prop_gtextFStretch ) )
2478             bTextPathFitShape = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x400 ) != 0;
2479         else
2480         {
2481             bTextPathFitShape = true;
2482             switch( rObjData.eShapeType )
2483             {
2484                 case mso_sptTextArchUpCurve :
2485                 case mso_sptTextArchDownCurve :
2486                 case mso_sptTextCircleCurve :
2487                 case mso_sptTextButtonCurve :
2488                     bTextPathFitShape = false;
2489                     break;
2490                 default : break;
2491             }
2492         }
2493         EnhancedCustomShapeTextPathMode eTextPathMode( EnhancedCustomShapeTextPathMode_NORMAL );
2494         if ( bTextPathFitShape )
2495             eTextPathMode = EnhancedCustomShapeTextPathMode_SHAPE;
2496         else if ( bTextPathFitPath )
2497             eTextPathMode = EnhancedCustomShapeTextPathMode_PATH;
2498         aProp.Name = "TextPathMode";
2499         aProp.Value <<= eTextPathMode;
2500         aTextPathPropVec.push_back( aProp );
2501 
2502         // ScaleX
2503         bool bTextPathScaleX = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x40 ) != 0;
2504         aProp.Name = "ScaleX";
2505         aProp.Value <<= bTextPathScaleX;
2506         aTextPathPropVec.push_back( aProp );
2507         // SameLetterHeights
2508         bool bSameLetterHeight = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x80 ) != 0;
2509         aProp.Name = "SameLetterHeights";
2510         aProp.Value <<= bSameLetterHeight;
2511         aTextPathPropVec.push_back( aProp );
2512 
2513         // pushing the whole TextPath element
2514         aProp.Name = "TextPath";
2515         aProp.Value <<= comphelper::containerToSequence(aTextPathPropVec);
2516         aPropVec.push_back( aProp );
2517     }
2518 
2519     // "AdjustmentValues" // The AdjustmentValues are imported at last, because depending to the type of the
2520     //////////////////////// handle (POLAR) we will convert the adjustment value from a fixed float to double
2521 
2522     // checking the last used adjustment handle, so we can determine how many handles are to allocate
2523     sal_uInt32 i = DFF_Prop_adjust10Value;
2524     while ( ( i >= DFF_Prop_adjustValue ) && !IsProperty( i ) )
2525         i--;
2526     sal_Int32 nAdjustmentValues = ( i - DFF_Prop_adjustValue ) + 1;
2527     if ( nAdjustmentValues )
2528     {
2529         uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentSeq( nAdjustmentValues );
2530         while( --nAdjustmentValues >= 0 )
2531         {
2532             sal_Int32 nValue = 0;
2533             beans::PropertyState ePropertyState = beans::PropertyState_DEFAULT_VALUE;
2534             if ( IsProperty( i ) )
2535             {
2536                 nValue = GetPropertyValue( i, 0 );
2537                 ePropertyState = beans::PropertyState_DIRECT_VALUE;
2538             }
2539             if ( nAdjustmentsWhichNeedsToBeConverted & ( 1 << ( i - DFF_Prop_adjustValue ) ) )
2540             {
2541                 double fValue = nValue;
2542                 fValue /= 65536;
2543                 aAdjustmentSeq[ nAdjustmentValues ].Value <<= fValue;
2544             }
2545             else
2546                 aAdjustmentSeq[ nAdjustmentValues ].Value <<= nValue;
2547             aAdjustmentSeq[ nAdjustmentValues ].State = ePropertyState;
2548             i--;
2549         }
2550         aProp.Name = "AdjustmentValues";
2551         aProp.Value <<= aAdjustmentSeq;
2552         aPropVec.push_back( aProp );
2553     }
2554 
2555     // creating the whole property set
2556     rSet.Put( SdrCustomShapeGeometryItem( comphelper::containerToSequence(aPropVec) ) );
2557 }
2558 
2559 void DffPropertyReader::ApplyAttributes( SvStream& rIn, SfxItemSet& rSet ) const
2560 {
2561     DffRecordHeader aHdTemp;
2562     DffObjData aDffObjTemp( aHdTemp, tools::Rectangle(), 0 );
2563     ApplyAttributes( rIn, rSet, aDffObjTemp );
2564 }
2565 
2566 void DffPropertyReader::ApplyAttributes( SvStream& rIn, SfxItemSet& rSet, DffObjData const & rObjData ) const
2567 {
2568     bool bHasShadow = false;
2569     bool bNonZeroShadowOffset = false;
2570 
2571     if ( IsProperty( DFF_Prop_gtextSize ) )
2572         rSet.Put( SvxFontHeightItem( rManager.ScalePt( GetPropertyValue( DFF_Prop_gtextSize, 0 ) ), 100, EE_CHAR_FONTHEIGHT ) );
2573     sal_uInt32 nFontAttributes = GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 );
2574     if ( nFontAttributes & 0x20 )
2575         rSet.Put( SvxWeightItem( (nFontAttributes & 0x20) ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT ) );
2576     if ( nFontAttributes & 0x10 )
2577         rSet.Put( SvxPostureItem( (nFontAttributes & 0x10) ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC ) );
2578     if ( nFontAttributes & 0x08 )
2579         rSet.Put( SvxUnderlineItem( (nFontAttributes & 0x08) ? LINESTYLE_SINGLE : LINESTYLE_NONE, EE_CHAR_UNDERLINE ) );
2580     if ( nFontAttributes & 0x40 )
2581         rSet.Put( SvxShadowedItem( (nFontAttributes & 0x40) != 0, EE_CHAR_SHADOW ) );
2582 //    if ( nFontAttributes & 0x02 )
2583 //        rSet.Put( SvxCaseMapItem( nFontAttributes & 0x02 ? SvxCaseMap::SmallCaps : SvxCaseMap::NotMapped ) );
2584     if ( nFontAttributes & 0x01 )
2585         rSet.Put( SvxCrossedOutItem( (nFontAttributes & 0x01) ? STRIKEOUT_SINGLE : STRIKEOUT_NONE, EE_CHAR_STRIKEOUT ) );
2586     if ( IsProperty( DFF_Prop_fillColor ) )
2587         rSet.Put( XFillColorItem( OUString(), rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillColor, 0 ), DFF_Prop_fillColor ) ) );
2588     if ( IsProperty( DFF_Prop_shadowColor ) )
2589         rSet.Put( makeSdrShadowColorItem( rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_shadowColor, 0 ), DFF_Prop_shadowColor ) ) );
2590     else
2591     {
2592         //The default value for this property is 0x00808080
2593         rSet.Put( makeSdrShadowColorItem( rManager.MSO_CLR_ToColor( 0x00808080, DFF_Prop_shadowColor ) ) );
2594     }
2595     if ( IsProperty( DFF_Prop_shadowOpacity ) )
2596         rSet.Put( makeSdrShadowTransparenceItem( static_cast<sal_uInt16>( ( 0x10000 - GetPropertyValue( DFF_Prop_shadowOpacity, 0 ) ) / 655 ) ) );
2597     if ( IsProperty( DFF_Prop_shadowOffsetX ) )
2598     {
2599         sal_Int32 nVal = static_cast< sal_Int32 >( GetPropertyValue( DFF_Prop_shadowOffsetX, 0 ) );
2600         rManager.ScaleEmu( nVal );
2601         rSet.Put( makeSdrShadowXDistItem( nVal ) );
2602         bNonZeroShadowOffset = ( nVal > 0 );
2603     }
2604     if ( IsProperty( DFF_Prop_shadowOffsetY ) )
2605     {
2606         sal_Int32 nVal = static_cast< sal_Int32 >( GetPropertyValue( DFF_Prop_shadowOffsetY, 0 ) );
2607         rManager.ScaleEmu( nVal );
2608         rSet.Put( makeSdrShadowYDistItem( nVal ) );
2609         bNonZeroShadowOffset = ( nVal > 0 );
2610     }
2611     if ( IsProperty( DFF_Prop_fshadowObscured ) )
2612     {
2613         bHasShadow = ( GetPropertyValue( DFF_Prop_fshadowObscured, 0 ) & 2 ) != 0;
2614         if ( bHasShadow )
2615         {
2616             if ( !IsProperty( DFF_Prop_shadowOffsetX ) )
2617                 rSet.Put( makeSdrShadowXDistItem( 35 ) );
2618             if ( !IsProperty( DFF_Prop_shadowOffsetY ) )
2619                 rSet.Put( makeSdrShadowYDistItem( 35 ) );
2620         }
2621     }
2622     if ( IsProperty( DFF_Prop_shadowType ) )
2623     {
2624         auto eShadowType = GetPropertyValue(DFF_Prop_shadowType, 0);
2625         if( eShadowType != mso_shadowOffset && !bNonZeroShadowOffset )
2626         {
2627             //0.12" == 173 twip == 302 100mm
2628             sal_uInt32 nDist = rManager.pSdrModel->GetScaleUnit() == MapUnit::MapTwip ? 173: 302;
2629             rSet.Put( makeSdrShadowXDistItem( nDist ) );
2630             rSet.Put( makeSdrShadowYDistItem( nDist ) );
2631         }
2632     }
2633     if ( bHasShadow )
2634     {
2635         static bool bCheckShadow(false); // loplugin:constvars:ignore
2636 
2637         // #i124477# Found no reason not to set shadow, esp. since it is applied to evtl. existing text
2638         // and will lead to an error if in PPT someone used text and added the object shadow to the
2639         // object carrying that text. I found no cases where this leads to problems (the old bugtracker
2640         // task #160376# from sj is unfortunately no longer available). Keeping the code for now
2641         // to allow easy fallback when this shows problems in the future
2642         if(bCheckShadow)
2643         {
2644             // #160376# sj: activating shadow only if fill and or linestyle is used
2645             // this is required because of the latest drawing layer core changes.
2646             // #i104085# is related to this.
2647             sal_uInt32 nLineFlags(GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 ));
2648             if(!IsHardAttribute( DFF_Prop_fLine ) && !IsCustomShapeStrokedByDefault( rObjData.eShapeType ))
2649                 nLineFlags &= ~0x08;
2650             sal_uInt32 nFillFlags(GetPropertyValue( DFF_Prop_fNoFillHitTest, 0 ));
2651             if(!IsHardAttribute( DFF_Prop_fFilled ) && !IsCustomShapeFilledByDefault( rObjData.eShapeType ))
2652                 nFillFlags &= ~0x10;
2653             if ( nFillFlags & 0x10 )
2654             {
2655                 auto eMSO_FillType = GetPropertyValue(DFF_Prop_fillType, mso_fillSolid);
2656                 switch( eMSO_FillType )
2657                 {
2658                     case mso_fillSolid :
2659                     case mso_fillPattern :
2660                     case mso_fillTexture :
2661                     case mso_fillPicture :
2662                     case mso_fillShade :
2663                     case mso_fillShadeCenter :
2664                     case mso_fillShadeShape :
2665                     case mso_fillShadeScale :
2666                     case mso_fillShadeTitle :
2667                     break;
2668                     default:
2669                         nFillFlags &=~0x10;         // no fillstyle used
2670                     break;
2671                 }
2672             }
2673             if ( ( ( nLineFlags & 0x08 ) == 0 ) && ( ( nFillFlags & 0x10 ) == 0 ) && ( rObjData.eShapeType != mso_sptPictureFrame ))    // if there is no fillstyle and linestyle
2674                 bHasShadow = false;                                             // we are turning shadow off.
2675         }
2676 
2677         if ( bHasShadow )
2678             rSet.Put( makeSdrShadowItem( bHasShadow ) );
2679     }
2680     ApplyLineAttributes( rSet, rObjData.eShapeType ); // #i28269#
2681     ApplyFillAttributes( rIn, rSet, rObjData );
2682     if ( rObjData.eShapeType != mso_sptNil || IsProperty( DFF_Prop_pVertices ) )
2683     {
2684         ApplyCustomShapeGeometryAttributes( rIn, rSet, rObjData );
2685         ApplyCustomShapeTextAttributes( rSet );
2686         if ( rManager.GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_EXCEL )
2687         {
2688             if ( mnFix16Angle || ( rObjData.nSpFlags & ShapeFlag::FlipV ) )
2689                 CheckAndCorrectExcelTextRotation( rIn, rSet, rObjData );
2690         }
2691     }
2692 }
2693 
2694 void DffPropertyReader::CheckAndCorrectExcelTextRotation( SvStream& rIn, SfxItemSet& rSet, DffObjData const & rObjData ) const
2695 {
2696     bool bRotateTextWithShape = rObjData.bRotateTextWithShape;
2697     if ( rObjData.bOpt2 )        // sj: #158494# is the second property set available ? if then we have to check the xml data of
2698     {                            // the shape, because the textrotation of Excel 2003 and greater versions is stored there
2699                                 // (upright property of the textbox)
2700         if ( rManager.pSecPropSet->SeekToContent( DFF_Prop_metroBlob, rIn ) )
2701         {
2702             sal_uInt32 nLen = rManager.pSecPropSet->GetPropertyValue( DFF_Prop_metroBlob, 0 );
2703             if ( nLen )
2704             {
2705                 css::uno::Sequence< sal_Int8 > aXMLDataSeq( nLen );
2706                 rIn.ReadBytes(aXMLDataSeq.getArray(), nLen);
2707                 css::uno::Reference< css::io::XInputStream > xInputStream
2708                     ( new ::comphelper::SequenceInputStream( aXMLDataSeq ) );
2709                 try
2710                 {
2711                     css::uno::Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
2712                     css::uno::Reference< css::embed::XStorage > xStorage
2713                         ( ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream(
2714                             OFOPXML_STORAGE_FORMAT_STRING, xInputStream, xContext, true ) );
2715                     if ( xStorage.is() )
2716                     {
2717                         css::uno::Reference< css::embed::XStorage >
2718                             xStorageDRS( xStorage->openStorageElement( "drs", css::embed::ElementModes::SEEKABLEREAD ) );
2719                         if ( xStorageDRS.is() )
2720                         {
2721                             css::uno::Reference< css::io::XStream > xShapeXMLStream( xStorageDRS->openStreamElement( "shapexml.xml", css::embed::ElementModes::SEEKABLEREAD ) );
2722                             if ( xShapeXMLStream.is() )
2723                             {
2724                                 css::uno::Reference< css::io::XInputStream > xShapeXMLInputStream( xShapeXMLStream->getInputStream() );
2725                                 if ( xShapeXMLInputStream.is() )
2726                                 {
2727                                     css::uno::Sequence< sal_Int8 > aSeq;
2728                                     sal_Int32 nBytesRead = xShapeXMLInputStream->readBytes( aSeq, 0x7fffffff );
2729                                     if ( nBytesRead )
2730                                     {    // for only one property I spare to use a XML parser at this point, this
2731                                         // should be enhanced if needed
2732 
2733                                         bRotateTextWithShape = true;    // using the correct xml default
2734                                         const char* pArry = reinterpret_cast< char* >( aSeq.getArray() );
2735                                         const char* const pUpright = "upright=";
2736                                         const char* pEnd = pArry + nBytesRead;
2737                                         const char* pPtr = pArry;
2738                                         while( ( pPtr + 12 ) < pEnd )
2739                                         {
2740                                             if ( !memcmp( pUpright, pPtr, 8 ) )
2741                                             {
2742                                                 bRotateTextWithShape = ( pPtr[ 9 ] != '1' ) && ( pPtr[ 9 ] != 't' );
2743                                                 break;
2744                                             }
2745                                             else
2746                                                 pPtr++;
2747                                         }
2748                                     }
2749                                 }
2750                             }
2751                         }
2752                     }
2753                 }
2754                 catch( css::uno::Exception& )
2755                 {
2756                 }
2757             }
2758         }
2759     }
2760     if ( bRotateTextWithShape )
2761         return;
2762 
2763     const css::uno::Any* pAny;
2764     SdrCustomShapeGeometryItem aGeometryItem(rSet.Get( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
2765     const OUString sTextRotateAngle( "TextRotateAngle" );
2766     pAny = aGeometryItem.GetPropertyValueByName( sTextRotateAngle );
2767     double fExtraTextRotateAngle = 0.0;
2768     if ( pAny )
2769         *pAny >>= fExtraTextRotateAngle;
2770 
2771     if ( rManager.mnFix16Angle )
2772         fExtraTextRotateAngle += mnFix16Angle.get() / 100.0;
2773     if ( rObjData.nSpFlags & ShapeFlag::FlipV )
2774         fExtraTextRotateAngle -= 180.0;
2775 
2776     css::beans::PropertyValue aTextRotateAngle;
2777     aTextRotateAngle.Name = sTextRotateAngle;
2778     aTextRotateAngle.Value <<= fExtraTextRotateAngle;
2779     aGeometryItem.SetPropertyValue( aTextRotateAngle );
2780     rSet.Put( aGeometryItem );
2781 }
2782 
2783 
2784 void DffPropertyReader::ImportGradientColor( SfxItemSet& aSet, sal_uInt32 eMSO_FillType, double dTrans , double dBackTrans) const
2785 {
2786     //MS Focus prop will impact the start and end color position. And AOO does not
2787     //support this prop. So need some swap for the two color to keep fidelity with AOO and MS shape.
2788     //So below var is defined.
2789     sal_Int32 nChgColors = 0;
2790     sal_Int32 nAngleFix16 = GetPropertyValue( DFF_Prop_fillAngle, 0 );
2791     if(nAngleFix16 >= 0)
2792         nChgColors ^= 1;
2793 
2794     //Translate a MS clockwise(+) or count clockwise angle(-) into an AOO count clock wise angle
2795     Degree10 nAngle( 3600 - ( ( Fix16ToAngle(nAngleFix16).get() + 5 ) / 10 ) );
2796     //Make sure this angle belongs to 0~3600
2797     while ( nAngle >= Degree10(3600) ) nAngle -= Degree10(3600);
2798     while ( nAngle < Degree10(0) ) nAngle += Degree10(3600);
2799 
2800     //Rotate angle
2801     if ( mbRotateGranientFillWithAngle )
2802     {
2803         sal_Int32 nRotateAngle = GetPropertyValue( DFF_Prop_Rotation, 0 );
2804         if(nRotateAngle)//fixed point number
2805             nRotateAngle = ( static_cast<sal_Int16>( nRotateAngle >> 16) * 100L ) + ( ( ( nRotateAngle & 0x0000ffff) * 100L ) >> 16 );
2806         nRotateAngle = ( nRotateAngle + 5 ) / 10 ;//round up
2807         //nAngle is a clockwise angle. If nRotateAngle is a clockwise angle, then gradient needs to be rotated a little less
2808         //or it needs to be rotated a little more
2809         nAngle -=  Degree10(nRotateAngle);
2810     }
2811     while ( nAngle >= Degree10(3600) ) nAngle -= Degree10(3600);
2812     while ( nAngle < Degree10(0) ) nAngle += Degree10(3600);
2813 
2814     css::awt::GradientStyle eGrad = css::awt::GradientStyle_LINEAR;
2815 
2816     sal_Int32 nFocus = GetPropertyValue( DFF_Prop_fillFocus, 0 );
2817     if ( !nFocus )
2818         nChgColors ^= 1;
2819     else if ( nFocus < 0 )//If it is a negative focus, the color will be swapped
2820     {
2821         nFocus = o3tl::saturating_toggle_sign(nFocus);
2822         nChgColors ^= 1;
2823     }
2824 
2825     if( nFocus > 40 && nFocus < 60 )
2826     {
2827         eGrad = css::awt::GradientStyle_AXIAL;//A axial gradient other than linear
2828         nChgColors ^= 1;
2829     }
2830     //if the type is linear or axial, just save focus to nFocusX and nFocusY for export
2831     //Core function does no need them. They serve for rect gradient(CenterXY).
2832     sal_uInt16 nFocusX = static_cast<sal_uInt16>(nFocus);
2833     sal_uInt16 nFocusY = static_cast<sal_uInt16>(nFocus);
2834 
2835     switch( eMSO_FillType )
2836     {
2837     case mso_fillShadeShape :
2838         {
2839             eGrad = css::awt::GradientStyle_RECT;
2840             nFocusY = nFocusX = 50;
2841             nChgColors ^= 1;
2842         }
2843         break;
2844     case mso_fillShadeCenter :
2845         {
2846             eGrad = css::awt::GradientStyle_RECT;
2847             //A MS fillTo prop specifies the relative position of the left boundary
2848             //of the center rectangle in a concentric shaded fill. Use 100 or 0 to keep fidelity
2849             nFocusX=(GetPropertyValue( DFF_Prop_fillToRight, 0 )==0x10000) ? 100 : 0;
2850             nFocusY=(GetPropertyValue( DFF_Prop_fillToBottom,0 )==0x10000) ? 100 : 0;
2851             nChgColors ^= 1;
2852         }
2853         break;
2854         default: break;
2855     }
2856 
2857     Color aCol1( rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillColor ) );
2858     Color aCol2( rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillBackColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillBackColor ) );
2859     if ( nChgColors )
2860     {
2861         //Swap start and end color
2862         Color aZwi( aCol1 );
2863         aCol1 = aCol2;
2864         aCol2 = aZwi;
2865         //Swap two colors' transparency
2866         double dTemp = dTrans;
2867         dTrans = dBackTrans;
2868         dBackTrans = dTemp;
2869     }
2870 
2871     //Construct gradient item
2872     XGradient aGrad( aCol2, aCol1, eGrad, nAngle, nFocusX, nFocusY );
2873     //Intensity has been merged into color. So here just set is as 100
2874     aGrad.SetStartIntens( 100 );
2875     aGrad.SetEndIntens( 100 );
2876     aSet.Put( XFillGradientItem( OUString(), aGrad ) );
2877     //Construct transparency item. This item can coordinate with both solid and gradient.
2878     if ( dTrans < 1.0 || dBackTrans < 1.0 )
2879     {
2880         sal_uInt8 nStartCol = static_cast<sal_uInt8>( (1 - dTrans )* 255 );
2881         sal_uInt8 nEndCol = static_cast<sal_uInt8>( ( 1- dBackTrans ) * 255 );
2882         aCol1 = Color(nStartCol, nStartCol, nStartCol);
2883         aCol2 = Color(nEndCol, nEndCol, nEndCol);
2884 
2885         XGradient aGrad2( aCol2 ,  aCol1 , eGrad, nAngle, nFocusX, nFocusY );
2886         aSet.Put( XFillFloatTransparenceItem( OUString(), aGrad2 ) );
2887     }
2888 }
2889 
2890 
2891 //- Record Manager ----------------------------------------------------------
2892 
2893 
2894 DffRecordList::DffRecordList( DffRecordList* pList ) :
2895     nCount                  ( 0 ),
2896     nCurrent                ( 0 ),
2897     pPrev                   ( pList )
2898 {
2899     if ( pList )
2900         pList->pNext.reset( this );
2901 }
2902 
2903 DffRecordList::~DffRecordList()
2904 {
2905 }
2906 
2907 DffRecordManager::DffRecordManager() :
2908     DffRecordList   ( nullptr ),
2909     pCList          ( static_cast<DffRecordList*>(this) )
2910 {
2911 }
2912 
2913 DffRecordManager::DffRecordManager( SvStream& rIn ) :
2914     DffRecordList   ( nullptr ),
2915     pCList          ( static_cast<DffRecordList*>(this) )
2916 {
2917     Consume( rIn );
2918 }
2919 
2920 void DffRecordManager::Consume( SvStream& rIn, sal_uInt32 nStOfs )
2921 {
2922     Clear();
2923     sal_uInt64 nOldPos = rIn.Tell();
2924     if ( !nStOfs )
2925     {
2926         DffRecordHeader aHd;
2927         bool bOk = ReadDffRecordHeader( rIn, aHd );
2928         if (bOk && aHd.nRecVer == DFF_PSFLAG_CONTAINER)
2929             nStOfs = aHd.GetRecEndFilePos();
2930     }
2931     if ( !nStOfs )
2932         return;
2933 
2934     pCList = this;
2935     while ( pCList->pNext )
2936         pCList = pCList->pNext.get();
2937     while (rIn.good() && ( ( rIn.Tell() + 8 ) <=  nStOfs ))
2938     {
2939         if ( pCList->nCount == DFF_RECORD_MANAGER_BUF_SIZE )
2940             pCList = new DffRecordList( pCList );
2941         if (!ReadDffRecordHeader(rIn, pCList->mHd[ pCList->nCount ]))
2942             break;
2943         bool bSeekSucceeded = pCList->mHd[ pCList->nCount++ ].SeekToEndOfRecord(rIn);
2944         if (!bSeekSucceeded)
2945             break;
2946     }
2947     rIn.Seek( nOldPos );
2948 }
2949 
2950 void DffRecordManager::Clear()
2951 {
2952     pCList = this;
2953     pNext.reset();
2954     nCurrent = 0;
2955     nCount = 0;
2956 }
2957 
2958 DffRecordHeader* DffRecordManager::Current()
2959 {
2960     DffRecordHeader* pRet = nullptr;
2961     if ( pCList->nCurrent < pCList->nCount )
2962         pRet = &pCList->mHd[ pCList->nCurrent ];
2963     return pRet;
2964 }
2965 
2966 DffRecordHeader* DffRecordManager::First()
2967 {
2968     DffRecordHeader* pRet = nullptr;
2969     pCList = this;
2970     if ( pCList->nCount )
2971     {
2972         pCList->nCurrent = 0;
2973         pRet = &pCList->mHd[ 0 ];
2974     }
2975     return pRet;
2976 }
2977 
2978 DffRecordHeader* DffRecordManager::Next()
2979 {
2980     DffRecordHeader* pRet = nullptr;
2981     sal_uInt32 nC = pCList->nCurrent + 1;
2982     if ( nC < pCList->nCount )
2983     {
2984         pCList->nCurrent++;
2985         pRet = &pCList->mHd[ nC ];
2986     }
2987     else if ( pCList->pNext )
2988     {
2989         pCList = pCList->pNext.get();
2990         pCList->nCurrent = 0;
2991         pRet = &pCList->mHd[ 0 ];
2992     }
2993     return pRet;
2994 }
2995 
2996 DffRecordHeader* DffRecordManager::Prev()
2997 {
2998     DffRecordHeader* pRet = nullptr;
2999     sal_uInt32 nCur = pCList->nCurrent;
3000     if ( !nCur && pCList->pPrev )
3001     {
3002         pCList = pCList->pPrev;
3003         nCur = pCList->nCount;
3004     }
3005     if ( nCur-- )
3006     {
3007         pCList->nCurrent = nCur;
3008         pRet = &pCList->mHd[ nCur ];
3009     }
3010     return pRet;
3011 }
3012 
3013 DffRecordHeader* DffRecordManager::Last()
3014 {
3015     DffRecordHeader* pRet = nullptr;
3016     while ( pCList->pNext )
3017         pCList = pCList->pNext.get();
3018     sal_uInt32 nCnt = pCList->nCount;
3019     if ( nCnt-- )
3020     {
3021         pCList->nCurrent = nCnt;
3022         pRet = &pCList->mHd[ nCnt ];
3023     }
3024     return pRet;
3025 }
3026 
3027 bool DffRecordManager::SeekToContent( SvStream& rIn, sal_uInt16 nRecId, DffSeekToContentMode eMode )
3028 {
3029     DffRecordHeader* pHd = GetRecordHeader( nRecId, eMode );
3030     if ( pHd )
3031     {
3032         pHd->SeekToContent( rIn );
3033         return true;
3034     }
3035     else
3036         return false;
3037 }
3038 
3039 DffRecordHeader* DffRecordManager::GetRecordHeader( sal_uInt16 nRecId, DffSeekToContentMode eMode )
3040 {
3041     sal_uInt32 nOldCurrent = pCList->nCurrent;
3042     DffRecordList* pOldList = pCList;
3043     DffRecordHeader* pHd;
3044 
3045     if ( eMode == SEEK_FROM_BEGINNING )
3046         pHd = First();
3047     else
3048         pHd = Next();
3049 
3050     while ( pHd )
3051     {
3052         if ( pHd->nRecType == nRecId )
3053             break;
3054         pHd = Next();
3055     }
3056     if ( !pHd && eMode == SEEK_FROM_CURRENT_AND_RESTART )
3057     {
3058         DffRecordHeader* pBreak = &pOldList->mHd[ nOldCurrent ];
3059         pHd = First();
3060         if ( pHd )
3061         {
3062             while ( pHd != pBreak )
3063             {
3064                 if ( pHd->nRecType == nRecId )
3065                     break;
3066                 pHd = Next();
3067             }
3068             if ( pHd->nRecType != nRecId )
3069                 pHd = nullptr;
3070         }
3071     }
3072     if ( !pHd )
3073     {
3074         pCList = pOldList;
3075         pOldList->nCurrent = nOldCurrent;
3076     }
3077     return pHd;
3078 }
3079 
3080 
3081 //  private methods
3082 
3083 
3084 bool CompareSvxMSDffShapeInfoById::operator() (
3085     std::shared_ptr<SvxMSDffShapeInfo> const& lhs,
3086     std::shared_ptr<SvxMSDffShapeInfo> const& rhs) const
3087 {
3088     return lhs->nShapeId < rhs->nShapeId;
3089 }
3090 
3091 bool CompareSvxMSDffShapeInfoByTxBxComp::operator() (
3092     std::shared_ptr<SvxMSDffShapeInfo> const& lhs,
3093     std::shared_ptr<SvxMSDffShapeInfo> const& rhs) const
3094 {
3095     return lhs->nTxBxComp < rhs->nTxBxComp;
3096 }
3097 
3098 void SvxMSDffManager::Scale( sal_Int32& rVal ) const
3099 {
3100     if ( bNeedMap )
3101         rVal = BigMulDiv( rVal, nMapMul, nMapDiv );
3102 }
3103 
3104 void SvxMSDffManager::Scale( Point& rPos ) const
3105 {
3106     rPos.AdjustX(nMapXOfs );
3107     rPos.AdjustY(nMapYOfs );
3108     if ( bNeedMap )
3109     {
3110         rPos.setX( BigMulDiv( rPos.X(), nMapMul, nMapDiv ) );
3111         rPos.setY( BigMulDiv( rPos.Y(), nMapMul, nMapDiv ) );
3112     }
3113 }
3114 
3115 void SvxMSDffManager::Scale( Size& rSiz ) const
3116 {
3117     if ( bNeedMap )
3118     {
3119         rSiz.setWidth( BigMulDiv( rSiz.Width(), nMapMul, nMapDiv ) );
3120         rSiz.setHeight( BigMulDiv( rSiz.Height(), nMapMul, nMapDiv ) );
3121     }
3122 }
3123 
3124 void SvxMSDffManager::ScaleEmu( sal_Int32& rVal ) const
3125 {
3126     rVal = BigMulDiv( rVal, nEmuMul, nEmuDiv );
3127 }
3128 
3129 sal_uInt32 SvxMSDffManager::ScalePt( sal_uInt32 nVal ) const
3130 {
3131     MapUnit eMap = pSdrModel->GetScaleUnit();
3132     Fraction aFact( GetMapFactor( MapUnit::MapPoint, eMap ).X() );
3133     tools::Long aMul = aFact.GetNumerator();
3134     tools::Long aDiv = aFact.GetDenominator() * 65536;
3135     aFact = Fraction( aMul, aDiv ); // try again to shorten it
3136     return BigMulDiv( nVal, aFact.GetNumerator(), aFact.GetDenominator() );
3137 }
3138 
3139 sal_Int32 SvxMSDffManager::ScalePoint( sal_Int32 nVal ) const
3140 {
3141     return BigMulDiv( nVal, nPntMul, nPntDiv );
3142 };
3143 
3144 void SvxMSDffManager::SetModel(SdrModel* pModel, tools::Long nApplicationScale)
3145 {
3146     pSdrModel = pModel;
3147     if( pModel && (0 < nApplicationScale) )
3148     {
3149         // PPT works in units of 576DPI
3150         // WW on the other side uses twips, i.e. 1440DPI.
3151         MapUnit eMap = pSdrModel->GetScaleUnit();
3152         Fraction aFact( GetMapFactor(MapUnit::MapInch, eMap).X() );
3153         tools::Long nMul=aFact.GetNumerator();
3154         tools::Long nDiv=aFact.GetDenominator()*nApplicationScale;
3155         aFact=Fraction(nMul,nDiv); // try again to shorten it
3156         // For 100TH_MM -> 2540/576=635/144
3157         // For Twip     -> 1440/576=5/2
3158         nMapMul  = aFact.GetNumerator();
3159         nMapDiv  = aFact.GetDenominator();
3160         bNeedMap = nMapMul!=nMapDiv;
3161 
3162         // MS-DFF-Properties are mostly given in EMU (English Metric Units)
3163         // 1mm=36000emu, 1twip=635emu
3164         aFact=GetMapFactor(MapUnit::Map100thMM,eMap).X();
3165         nMul=aFact.GetNumerator();
3166         nDiv=aFact.GetDenominator()*360;
3167         aFact=Fraction(nMul,nDiv); // try again to shorten it
3168         // For 100TH_MM ->                            1/360
3169         // For Twip     -> 14,40/(25,4*360)=144/91440=1/635
3170         nEmuMul=aFact.GetNumerator();
3171         nEmuDiv=aFact.GetDenominator();
3172 
3173         // And something for typographic Points
3174         aFact=GetMapFactor(MapUnit::MapPoint,eMap).X();
3175         nPntMul=aFact.GetNumerator();
3176         nPntDiv=aFact.GetDenominator();
3177     }
3178     else
3179     {
3180         pModel = nullptr;
3181         nMapMul = nMapDiv = nMapXOfs = nMapYOfs = nEmuMul = nEmuDiv = nPntMul = nPntDiv = 0;
3182         bNeedMap = false;
3183     }
3184 }
3185 
3186 bool SvxMSDffManager::SeekToShape( SvStream& rSt, SvxMSDffClientData* /* pClientData */, sal_uInt32 nId ) const
3187 {
3188     bool bRet = false;
3189     if ( !maFidcls.empty() )
3190     {
3191         sal_uInt64 nOldPos = rSt.Tell();
3192         sal_uInt32 nSec = ( nId >> 10 ) - 1;
3193         if ( nSec < mnIdClusters )
3194         {
3195             OffsetMap::const_iterator it = maDgOffsetTable.find( maFidcls[ nSec ].dgid );
3196             if ( it != maDgOffsetTable.end() )
3197             {
3198                 sal_uInt64 nOfs = it->second;
3199                 rSt.Seek( nOfs );
3200                 DffRecordHeader aEscherF002Hd;
3201                 bool bOk = ReadDffRecordHeader( rSt, aEscherF002Hd );
3202                 sal_uLong nEscherF002End = bOk ? aEscherF002Hd.GetRecEndFilePos() : 0;
3203                 while (rSt.good() && rSt.Tell() < nEscherF002End)
3204                 {
3205                     DffRecordHeader aEscherObjListHd;
3206                     if (!ReadDffRecordHeader(rSt, aEscherObjListHd))
3207                         break;
3208                     if ( aEscherObjListHd.nRecVer != 0xf )
3209                     {
3210                         bool bSeekSuccess = aEscherObjListHd.SeekToEndOfRecord(rSt);
3211                         if (!bSeekSuccess)
3212                             break;
3213                     }
3214                     else if ( aEscherObjListHd.nRecType == DFF_msofbtSpContainer )
3215                     {
3216                         DffRecordHeader aShapeHd;
3217                         if ( SeekToRec( rSt, DFF_msofbtSp, aEscherObjListHd.GetRecEndFilePos(), &aShapeHd ) )
3218                         {
3219                             sal_uInt32 nShapeId(0);
3220                             rSt.ReadUInt32( nShapeId );
3221                             if ( nId == nShapeId )
3222                             {
3223                                 aEscherObjListHd.SeekToBegOfRecord( rSt );
3224                                 bRet = true;
3225                                 break;
3226                             }
3227                         }
3228                         bool bSeekSuccess = aEscherObjListHd.SeekToEndOfRecord(rSt);
3229                         if (!bSeekSuccess)
3230                             break;
3231                     }
3232                 }
3233             }
3234         }
3235         if ( !bRet )
3236             rSt.Seek( nOldPos );
3237     }
3238     return bRet;
3239 }
3240 
3241 bool SvxMSDffManager::SeekToRec( SvStream& rSt, sal_uInt16 nRecId, sal_uLong nMaxFilePos, DffRecordHeader* pRecHd, sal_uLong nSkipCount )
3242 {
3243     bool bRet = false;
3244     sal_uInt64 nOldFPos = rSt.Tell(); // store FilePos to restore it later if necessary
3245     do
3246     {
3247         DffRecordHeader aHd;
3248         if (!ReadDffRecordHeader(rSt, aHd))
3249             break;
3250         if (aHd.nRecLen > nMaxLegalDffRecordLength)
3251             break;
3252         if ( aHd.nRecType == nRecId )
3253         {
3254             if ( nSkipCount )
3255                 nSkipCount--;
3256             else
3257             {
3258                 bRet = true;
3259                 if ( pRecHd != nullptr )
3260                     *pRecHd = aHd;
3261                 else
3262                 {
3263                     bool bSeekSuccess = aHd.SeekToBegOfRecord(rSt);
3264                     if (!bSeekSuccess)
3265                     {
3266                         bRet = false;
3267                         break;
3268                     }
3269                 }
3270             }
3271         }
3272         if ( !bRet )
3273         {
3274             bool bSeekSuccess = aHd.SeekToEndOfRecord(rSt);
3275             if (!bSeekSuccess)
3276                 break;
3277         }
3278     }
3279     while ( rSt.good() && rSt.Tell() < nMaxFilePos && !bRet );
3280     if ( !bRet )
3281         rSt.Seek( nOldFPos );  // restore original FilePos
3282     return bRet;
3283 }
3284 
3285 bool SvxMSDffManager::SeekToRec2( sal_uInt16 nRecId1, sal_uInt16 nRecId2, sal_uLong nMaxFilePos ) const
3286 {
3287     bool bRet = false;
3288     sal_uInt64 nOldFPos = rStCtrl.Tell();   // remember FilePos for conditionally later restoration
3289     do
3290     {
3291         DffRecordHeader aHd;
3292         if (!ReadDffRecordHeader(rStCtrl, aHd))
3293             break;
3294         if ( aHd.nRecType == nRecId1 || aHd.nRecType == nRecId2 )
3295         {
3296             bRet = true;
3297             bool bSeekSuccess = aHd.SeekToBegOfRecord(rStCtrl);
3298             if (!bSeekSuccess)
3299             {
3300                 bRet = false;
3301                 break;
3302             }
3303         }
3304         if ( !bRet )
3305         {
3306             bool bSeekSuccess = aHd.SeekToEndOfRecord(rStCtrl);
3307             if (!bSeekSuccess)
3308                 break;
3309         }
3310     }
3311     while ( rStCtrl.good() && rStCtrl.Tell() < nMaxFilePos && !bRet );
3312     if ( !bRet )
3313         rStCtrl.Seek( nOldFPos ); // restore FilePos
3314     return bRet;
3315 }
3316 
3317 
3318 bool SvxMSDffManager::GetColorFromPalette( sal_uInt16 /* nNum */, Color& rColor ) const
3319 {
3320     // This method has to be overwritten in the class
3321     // derived for the excel export
3322     rColor = COL_WHITE;
3323     return true;
3324 }
3325 
3326 // sj: the documentation is not complete, especially in ppt the normal rgb for text
3327 // color is written as 0xfeRRGGBB, this can't be explained by the documentation, nearly
3328 // every bit in the upper code is set -> so there seems to be a special handling for
3329 // ppt text colors, i decided not to fix this in MSO_CLR_ToColor because of possible
3330 // side effects, instead MSO_TEXT_CLR_ToColor is called for PPT text colors, to map
3331 // the color code to something that behaves like the other standard color codes used by
3332 // fill and line color
3333 Color SvxMSDffManager::MSO_TEXT_CLR_ToColor( sal_uInt32 nColorCode ) const
3334 {
3335     // for text colors: Header is 0xfeRRGGBB
3336     if ( ( nColorCode & 0xfe000000 ) == 0xfe000000 )
3337         nColorCode &= 0x00ffffff;
3338     else
3339     {
3340         // for colorscheme colors the color index are the lower three bits of the upper byte
3341         if ( ( nColorCode & 0xf8000000 ) == 0 ) // this must be a colorscheme index
3342         {
3343             nColorCode >>= 24;
3344             nColorCode |= 0x8000000;
3345         }
3346     }
3347     return MSO_CLR_ToColor( nColorCode );
3348 }
3349 
3350 Color SvxMSDffManager::MSO_CLR_ToColor( sal_uInt32 nColorCode, sal_uInt16 nContentProperty ) const
3351 {
3352     Color aColor( mnDefaultColor );
3353 
3354     // for text colors: Header is 0xfeRRGGBB
3355     if ( ( nColorCode & 0xfe000000 ) == 0xfe000000 )    // sj: it needs to be checked if 0xfe is used in
3356         nColorCode &= 0x00ffffff;                       // other cases than ppt text -> if not this code can be removed
3357 
3358     sal_uInt8 nUpper = static_cast<sal_uInt8>( nColorCode >> 24 );
3359 
3360     // sj: below change from 0x1b to 0x19 was done because of i84812 (0x02 -> rgb color),
3361     // now I have some problems to fix i104685 (there the color value is 0x02000000 which requires
3362     // a 0x2 scheme color to be displayed properly), the color docu seems to be incomplete
3363     if( nUpper & 0x19 )      // if( nUpper & 0x1f )
3364     {
3365         if( ( nUpper & 0x08 ) || ( ( nUpper & 0x10 ) == 0 ) )
3366         {
3367             // SCHEMECOLOR
3368             if ( !GetColorFromPalette( ( nUpper & 8 ) ? static_cast<sal_uInt16>(nColorCode) : nUpper, aColor ) )
3369             {
3370                 switch( nContentProperty )
3371                 {
3372                     case DFF_Prop_pictureTransparent :
3373                     case DFF_Prop_shadowColor :
3374                     case DFF_Prop_fillBackColor :
3375                     case DFF_Prop_fillColor :
3376                         aColor = COL_WHITE;
3377                     break;
3378                     case DFF_Prop_lineColor :
3379                     {
3380                         aColor = COL_BLACK;
3381                     }
3382                     break;
3383                 }
3384             }
3385         }
3386         else    // SYSCOLOR
3387         {
3388             const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
3389 
3390             sal_uInt16 nParameter = sal_uInt16(( nColorCode >> 16 ) & 0x00ff);  // the HiByte of nParameter is not zero, an exclusive AND is helping :o
3391             sal_uInt16 nFunctionBits = static_cast<sal_uInt16>( ( nColorCode & 0x00000f00 ) >> 8 );
3392             sal_uInt16 nAdditionalFlags = static_cast<sal_uInt16>( ( nColorCode & 0x0000f000) >> 8 );
3393             sal_uInt16 nColorIndex = sal_uInt16(nColorCode & 0x00ff);
3394             sal_uInt32 nPropColor = 0;
3395 
3396             sal_uInt16  nCProp = 0;
3397 
3398             switch ( nColorIndex )
3399             {
3400                 case mso_syscolorButtonFace :           aColor = rStyleSettings.GetFaceColor(); break;
3401                 case mso_syscolorWindowText :           aColor = rStyleSettings.GetWindowTextColor(); break;
3402                 case mso_syscolorMenu :                 aColor = rStyleSettings.GetMenuColor(); break;
3403                 case mso_syscolor3DLight :
3404                 case mso_syscolorButtonHighlight :
3405                 case mso_syscolorHighlight :            aColor = rStyleSettings.GetHighlightColor(); break;
3406                 case mso_syscolorHighlightText :        aColor = rStyleSettings.GetHighlightTextColor(); break;
3407                 case mso_syscolorCaptionText :          aColor = rStyleSettings.GetMenuTextColor(); break;
3408                 case mso_syscolorActiveCaption :        aColor = rStyleSettings.GetHighlightColor(); break;
3409                 case mso_syscolorButtonShadow :         aColor = rStyleSettings.GetShadowColor(); break;
3410                 case mso_syscolorButtonText :           aColor = rStyleSettings.GetButtonTextColor(); break;
3411                 case mso_syscolorGrayText :             aColor = rStyleSettings.GetDeactiveColor(); break;
3412                 case mso_syscolorInactiveCaption :      aColor = rStyleSettings.GetDeactiveColor(); break;
3413                 case mso_syscolorInactiveCaptionText :  aColor = rStyleSettings.GetDeactiveColor(); break;
3414                 case mso_syscolorInfoBackground :       aColor = rStyleSettings.GetFaceColor(); break;
3415                 case mso_syscolorInfoText :             aColor = rStyleSettings.GetLabelTextColor(); break;
3416                 case mso_syscolorMenuText :             aColor = rStyleSettings.GetMenuTextColor(); break;
3417                 case mso_syscolorScrollbar :            aColor = rStyleSettings.GetFaceColor(); break;
3418                 case mso_syscolorWindow :               aColor = rStyleSettings.GetWindowColor(); break;
3419                 case mso_syscolorWindowFrame :          aColor = rStyleSettings.GetWindowColor(); break;
3420 
3421                 case mso_colorFillColor :
3422                 {
3423                     nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff );
3424                     nCProp = DFF_Prop_fillColor;
3425                 }
3426                 break;
3427                 case mso_colorLineOrFillColor :     // ( use the line color only if there is a line )
3428                 {
3429                     if ( GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 ) & 8 )
3430                     {
3431                         nPropColor = GetPropertyValue( DFF_Prop_lineColor, 0 );
3432                         nCProp = DFF_Prop_lineColor;
3433                     }
3434                     else
3435                     {
3436                         nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff );
3437                         nCProp = DFF_Prop_fillColor;
3438                     }
3439                 }
3440                 break;
3441                 case mso_colorLineColor :
3442                 {
3443                     nPropColor = GetPropertyValue( DFF_Prop_lineColor, 0 );
3444                     nCProp = DFF_Prop_lineColor;
3445                 }
3446                 break;
3447                 case mso_colorShadowColor :
3448                 {
3449                     nPropColor = GetPropertyValue( DFF_Prop_shadowColor, 0x808080 );
3450                     nCProp = DFF_Prop_shadowColor;
3451                 }
3452                 break;
3453                 case mso_colorThis :                // ( use this color ... )
3454                 {
3455                     nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff );  //?????????????
3456                     nCProp = DFF_Prop_fillColor;
3457                 }
3458                 break;
3459                 case mso_colorFillBackColor :
3460                 {
3461                     nPropColor = GetPropertyValue( DFF_Prop_fillBackColor, 0xffffff );
3462                     nCProp = DFF_Prop_fillBackColor;
3463                 }
3464                 break;
3465                 case mso_colorLineBackColor :
3466                 {
3467                     nPropColor = GetPropertyValue( DFF_Prop_lineBackColor, 0xffffff );
3468                     nCProp = DFF_Prop_lineBackColor;
3469                 }
3470                 break;
3471                 case mso_colorFillThenLine :        // ( use the fillcolor unless no fill and line )
3472                 {
3473                     nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff );  //?????????????
3474                     nCProp = DFF_Prop_fillColor;
3475                 }
3476                 break;
3477                 case mso_colorIndexMask :           // ( extract the color index ) ?
3478                 {
3479                     nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff );  //?????????????
3480                     nCProp = DFF_Prop_fillColor;
3481                 }
3482                 break;
3483             }
3484             if ( nCProp && ( nPropColor & 0x10000000 ) == 0 )       // beware of looping recursive
3485                 aColor = MSO_CLR_ToColor( nPropColor, nCProp );
3486 
3487             if( nAdditionalFlags & 0x80 )           // make color gray
3488             {
3489                 sal_uInt8 nZwi = aColor.GetLuminance();
3490                 aColor = Color( nZwi, nZwi, nZwi );
3491             }
3492             switch( nFunctionBits )
3493             {
3494                 case 0x01 :     // darken color by parameter
3495                 {
3496                     aColor.SetRed( sal::static_int_cast< sal_uInt8 >( ( nParameter * aColor.GetRed() ) >> 8 ) );
3497                     aColor.SetGreen( sal::static_int_cast< sal_uInt8 >( ( nParameter * aColor.GetGreen() ) >> 8 ) );
3498                     aColor.SetBlue( sal::static_int_cast< sal_uInt8 >( ( nParameter * aColor.GetBlue() ) >> 8 ) );
3499                 }
3500                 break;
3501                 case 0x02 :     // lighten color by parameter
3502                 {
3503                     sal_uInt16 nInvParameter = ( 0x00ff - nParameter ) * 0xff;
3504                     aColor.SetRed( sal::static_int_cast< sal_uInt8 >( ( nInvParameter + ( nParameter * aColor.GetRed() ) ) >> 8 ) );
3505                     aColor.SetGreen( sal::static_int_cast< sal_uInt8 >( ( nInvParameter + ( nParameter * aColor.GetGreen() ) ) >> 8 ) );
3506                     aColor.SetBlue( sal::static_int_cast< sal_uInt8 >( ( nInvParameter + ( nParameter * aColor.GetBlue() ) ) >> 8 ) );
3507                 }
3508                 break;
3509                 case 0x03 :     // add grey level RGB(p,p,p)
3510                 {
3511                     sal_Int16 nR = static_cast<sal_Int16>(aColor.GetRed()) + static_cast<sal_Int16>(nParameter);
3512                     sal_Int16 nG = static_cast<sal_Int16>(aColor.GetGreen()) + static_cast<sal_Int16>(nParameter);
3513                     sal_Int16 nB = static_cast<sal_Int16>(aColor.GetBlue()) + static_cast<sal_Int16>(nParameter);
3514                     if ( nR > 0x00ff )
3515                         nR = 0x00ff;
3516                     if ( nG > 0x00ff )
3517                         nG = 0x00ff;
3518                     if ( nB > 0x00ff )
3519                         nB = 0x00ff;
3520                     aColor = Color( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
3521                 }
3522                 break;
3523                 case 0x04 :     // subtract grey level RGB(p,p,p)
3524                 {
3525                     sal_Int16 nR = static_cast<sal_Int16>(aColor.GetRed()) - static_cast<sal_Int16>(nParameter);
3526                     sal_Int16 nG = static_cast<sal_Int16>(aColor.GetGreen()) - static_cast<sal_Int16>(nParameter);
3527                     sal_Int16 nB = static_cast<sal_Int16>(aColor.GetBlue()) - static_cast<sal_Int16>(nParameter);
3528                     if ( nR < 0 )
3529                         nR = 0;
3530                     if ( nG < 0 )
3531                         nG = 0;
3532                     if ( nB < 0 )
3533                         nB = 0;
3534                     aColor = Color( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
3535                 }
3536                 break;
3537                 case 0x05 :     // subtract from gray level RGB(p,p,p)
3538                 {
3539                     sal_Int16 nR = static_cast<sal_Int16>(nParameter) - static_cast<sal_Int16>(aColor.GetRed());
3540                     sal_Int16 nG = static_cast<sal_Int16>(nParameter) - static_cast<sal_Int16>(aColor.GetGreen());
3541                     sal_Int16 nB = static_cast<sal_Int16>(nParameter) - static_cast<sal_Int16>(aColor.GetBlue());
3542                     if ( nR < 0 )
3543                         nR = 0;
3544                     if ( nG < 0 )
3545                         nG = 0;
3546                     if ( nB < 0 )
3547                         nB = 0;
3548                     aColor = Color( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
3549                 }
3550                 break;
3551                 case 0x06 :     // per component: black if < p, white if >= p
3552                 {
3553                     aColor.SetRed( aColor.GetRed() < nParameter ? 0x00 : 0xff );
3554                     aColor.SetGreen( aColor.GetGreen() < nParameter ? 0x00 : 0xff );
3555                     aColor.SetBlue( aColor.GetBlue() < nParameter ? 0x00 : 0xff );
3556                 }
3557                 break;
3558             }
3559             if ( nAdditionalFlags & 0x40 )                  // top-bit invert
3560                 aColor = Color( aColor.GetRed() ^ 0x80, aColor.GetGreen() ^ 0x80, aColor.GetBlue() ^ 0x80 );
3561 
3562             if ( nAdditionalFlags & 0x20 )                  // invert color
3563                 aColor = Color(0xff - aColor.GetRed(), 0xff - aColor.GetGreen(), 0xff - aColor.GetBlue());
3564         }
3565     }
3566     else if ( ( nUpper & 4 ) && ( ( nColorCode & 0xfffff8 ) == 0 ) )
3567     {   // case of nUpper == 4 powerpoint takes this as argument for a colorschemecolor
3568         GetColorFromPalette( nUpper, aColor );
3569     }
3570     else    // attributed hard, maybe with hint to SYSTEMRGB
3571         aColor = Color( static_cast<sal_uInt8>(nColorCode), static_cast<sal_uInt8>( nColorCode >> 8 ), static_cast<sal_uInt8>( nColorCode >> 16 ) );
3572     return aColor;
3573 }
3574 
3575 void SvxMSDffManager::ReadObjText( SvStream& rStream, SdrObject* pObj )
3576 {
3577     DffRecordHeader aRecHd;
3578     if (!ReadDffRecordHeader(rStream, aRecHd))
3579         return;
3580     if( aRecHd.nRecType != DFF_msofbtClientTextbox && aRecHd.nRecType != 0x1022 )
3581         return;
3582 
3583     while (rStream.good() && rStream.Tell() < aRecHd.GetRecEndFilePos())
3584     {
3585         DffRecordHeader aHd;
3586         if (!ReadDffRecordHeader(rStream, aHd))
3587             break;
3588         switch( aHd.nRecType )
3589         {
3590             case DFF_PST_TextBytesAtom:
3591             case DFF_PST_TextCharsAtom:
3592                 {
3593                     bool bUniCode = ( aHd.nRecType == DFF_PST_TextCharsAtom );
3594                     sal_uInt32 nBytes = aHd.nRecLen;
3595                     OUString aStr = MSDFFReadZString( rStream, nBytes, bUniCode );
3596                     ReadObjText( aStr, pObj );
3597                 }
3598                 break;
3599             default:
3600                 break;
3601         }
3602         bool bSeekSuccess = aHd.SeekToEndOfRecord(rStream);
3603         if (!bSeekSuccess)
3604             break;
3605     }
3606 }
3607 
3608 // sj: I just want to set a string for a text object that may contain multiple
3609 // paragraphs. If I now take a look at the following code I get the impression that
3610 // our outliner is too complicate to be used properly,
3611 void SvxMSDffManager::ReadObjText( const OUString& rText, SdrObject* pObj )
3612 {
3613     SdrTextObj* pText = dynamic_cast<SdrTextObj*>( pObj  );
3614     if ( !pText )
3615         return;
3616 
3617     SdrOutliner& rOutliner = pText->ImpGetDrawOutliner();
3618     rOutliner.Init( OutlinerMode::TextObject );
3619 
3620     bool bOldUpdateMode = rOutliner.GetUpdateMode();
3621     rOutliner.SetUpdateMode( false );
3622     rOutliner.SetVertical( pText->IsVerticalWriting() );
3623 
3624     sal_Int32 nParaIndex = 0;
3625     sal_Int32 nParaSize;
3626     const sal_Unicode* pBuf = rText.getStr();
3627     const sal_Unicode* pEnd = rText.getStr() + rText.getLength();
3628 
3629     while( pBuf < pEnd )
3630     {
3631         const sal_Unicode* pCurrent = pBuf;
3632 
3633         for ( nParaSize = 0; pBuf < pEnd; )
3634         {
3635             sal_Unicode nChar = *pBuf++;
3636             if ( nChar == 0xa )
3637             {
3638                 if ( ( pBuf < pEnd ) && ( *pBuf == 0xd ) )
3639                     pBuf++;
3640                 break;
3641             }
3642             else if ( nChar == 0xd )
3643             {
3644                 if ( ( pBuf < pEnd ) && ( *pBuf == 0xa ) )
3645                     pBuf++;
3646                 break;
3647             }
3648             else
3649                 ++nParaSize;
3650         }
3651         ESelection aSelection( nParaIndex, 0, nParaIndex, 0 );
3652         OUString aParagraph( pCurrent, nParaSize );
3653         if ( !nParaIndex && aParagraph.isEmpty() )              // SJ: we are crashing if the first paragraph is empty ?
3654             aParagraph += " ";                   // otherwise these two lines can be removed.
3655         rOutliner.Insert( aParagraph, nParaIndex );
3656         rOutliner.SetParaAttribs( nParaIndex, rOutliner.GetEmptyItemSet() );
3657 
3658         SfxItemSet aParagraphAttribs( rOutliner.GetEmptyItemSet() );
3659         if ( !aSelection.nStartPos )
3660             aParagraphAttribs.Put( SfxBoolItem( EE_PARA_BULLETSTATE, false ) );
3661         aSelection.nStartPos = 0;
3662         rOutliner.QuickSetAttribs( aParagraphAttribs, aSelection );
3663         nParaIndex++;
3664     }
3665     std::unique_ptr<OutlinerParaObject> pNewText = rOutliner.CreateParaObject();
3666     rOutliner.Clear();
3667     rOutliner.SetUpdateMode( bOldUpdateMode );
3668     pText->SetOutlinerParaObject( std::move(pNewText) );
3669 }
3670 
3671 //static
3672 OUString SvxMSDffManager::MSDFFReadZString(SvStream& rIn,
3673     sal_uInt32 nLen, bool bUniCode)
3674 {
3675     if (!nLen)
3676         return OUString();
3677 
3678     OUString sBuf;
3679 
3680     if( bUniCode )
3681         sBuf = read_uInt16s_ToOUString(rIn, nLen/2);
3682     else
3683         sBuf = read_uInt8s_ToOUString(rIn, nLen, RTL_TEXTENCODING_MS_1252);
3684 
3685     return comphelper::string::stripEnd(sBuf, 0);
3686 }
3687 
3688 static Size lcl_GetPrefSize(const Graphic& rGraf, const MapMode& aWanted)
3689 {
3690     MapMode aPrefMapMode(rGraf.GetPrefMapMode());
3691     if (aPrefMapMode == aWanted)
3692         return rGraf.GetPrefSize();
3693     Size aRetSize;
3694     if (aPrefMapMode.GetMapUnit() == MapUnit::MapPixel)
3695     {
3696         aRetSize = Application::GetDefaultDevice()->PixelToLogic(
3697             rGraf.GetPrefSize(), aWanted);
3698     }
3699     else
3700     {
3701         aRetSize = OutputDevice::LogicToLogic(
3702             rGraf.GetPrefSize(), rGraf.GetPrefMapMode(), aWanted);
3703     }
3704     return aRetSize;
3705 }
3706 
3707 // sj: if the parameter pSet is null, then the resulting crop bitmap will be stored in rGraf,
3708 // otherwise rGraf is untouched and pSet is used to store the corresponding SdrGrafCropItem
3709 static void lcl_ApplyCropping( const DffPropSet& rPropSet, SfxItemSet* pSet, Graphic& rGraf )
3710 {
3711     sal_Int32 nCropTop      = static_cast<sal_Int32>(rPropSet.GetPropertyValue( DFF_Prop_cropFromTop, 0 ));
3712     sal_Int32 nCropBottom   = static_cast<sal_Int32>(rPropSet.GetPropertyValue( DFF_Prop_cropFromBottom, 0 ));
3713     sal_Int32 nCropLeft     = static_cast<sal_Int32>(rPropSet.GetPropertyValue( DFF_Prop_cropFromLeft, 0 ));
3714     sal_Int32 nCropRight    = static_cast<sal_Int32>(rPropSet.GetPropertyValue( DFF_Prop_cropFromRight, 0 ));
3715 
3716     if( !(nCropTop || nCropBottom || nCropLeft || nCropRight) )
3717         return;
3718 
3719     double      fFactor;
3720     Size        aCropSize;
3721     BitmapEx    aCropBitmap;
3722     sal_uInt32  nTop( 0 ),  nBottom( 0 ), nLeft( 0 ), nRight( 0 );
3723 
3724     // Cropping has to be applied on a loaded graphic.
3725     rGraf.makeAvailable();
3726 
3727     if ( pSet ) // use crop attributes ?
3728         aCropSize = lcl_GetPrefSize(rGraf, MapMode(MapUnit::Map100thMM));
3729     else
3730     {
3731         aCropBitmap = rGraf.GetBitmapEx();
3732         aCropSize = aCropBitmap.GetSizePixel();
3733     }
3734     if ( nCropTop )
3735     {
3736         fFactor = static_cast<double>(nCropTop) / 65536.0;
3737         nTop = static_cast<sal_uInt32>( ( static_cast<double>( aCropSize.Height() + 1 ) * fFactor ) + 0.5 );
3738     }
3739     if ( nCropBottom )
3740     {
3741         fFactor = static_cast<double>(nCropBottom) / 65536.0;
3742         nBottom = static_cast<sal_uInt32>( ( static_cast<double>( aCropSize.Height() + 1 ) * fFactor ) + 0.5 );
3743     }
3744     if ( nCropLeft )
3745     {
3746         fFactor = static_cast<double>(nCropLeft) / 65536.0;
3747         nLeft = static_cast<sal_uInt32>( ( static_cast<double>( aCropSize.Width() + 1 ) * fFactor ) + 0.5 );
3748     }
3749     if ( nCropRight )
3750     {
3751         fFactor = static_cast<double>(nCropRight) / 65536.0;
3752         nRight = static_cast<sal_uInt32>( ( static_cast<double>( aCropSize.Width() + 1 ) * fFactor ) + 0.5 );
3753     }
3754     if ( pSet ) // use crop attributes ?
3755         pSet->Put( SdrGrafCropItem( nLeft, nTop, nRight, nBottom ) );
3756     else
3757     {
3758         tools::Rectangle aCropRect( nLeft, nTop, aCropSize.Width() - nRight, aCropSize.Height() - nBottom );
3759         aCropBitmap.Crop( aCropRect );
3760         rGraf = aCropBitmap;
3761     }
3762 }
3763 
3764 SdrObject* SvxMSDffManager::ImportGraphic( SvStream& rSt, SfxItemSet& rSet, const DffObjData& rObjData )
3765 {
3766     SdrObject*  pRet = nullptr;
3767     OUString    aLinkFileName;
3768     tools::Rectangle   aVisArea;
3769 
3770     auto eFlags = GetPropertyValue(DFF_Prop_pibFlags, mso_blipflagDefault);
3771     sal_uInt32 nBlipId = GetPropertyValue( DFF_Prop_pib, 0 );
3772     bool bGrfRead = false,
3773 
3774     // Graphic linked
3775     bLinkGrf = 0 != ( eFlags & mso_blipflagLinkToFile );
3776     {
3777         OUString aFileName;
3778         Graphic aGraf;  // be sure this graphic is deleted before swapping out
3779         if( SeekToContent( DFF_Prop_pibName, rSt ) )
3780             aFileName = MSDFFReadZString( rSt, GetPropertyValue( DFF_Prop_pibName, 0 ), true );
3781 
3782         //   AND, OR the following:
3783         if( !( eFlags & mso_blipflagDoNotSave ) ) // Graphic embedded
3784         {
3785             bGrfRead = GetBLIP( nBlipId, aGraf, &aVisArea );
3786             if ( !bGrfRead )
3787             {
3788                 /*
3789                 Still no luck, lets look at the end of this record for a FBSE pool,
3790                 this fallback is a specific case for how word does it sometimes
3791                 */
3792                 bool bOk = rObjData.rSpHd.SeekToEndOfRecord( rSt );
3793                 DffRecordHeader aHd;
3794                 if (bOk)
3795                 {
3796                     bOk = ReadDffRecordHeader(rSt, aHd);
3797                 }
3798                 if (bOk && DFF_msofbtBSE == aHd.nRecType)
3799                 {
3800                     const sal_uLong nSkipBLIPLen = 20;
3801                     const sal_uLong nSkipShapePos = 4;
3802                     const sal_uLong nSkipBLIP = 4;
3803                     const sal_uLong nSkip =
3804                         nSkipBLIPLen + 4 + nSkipShapePos + 4 + nSkipBLIP;
3805 
3806                     if (nSkip <= aHd.nRecLen)
3807                     {
3808                         rSt.SeekRel(nSkip);
3809                         if (ERRCODE_NONE == rSt.GetError())
3810                             bGrfRead = GetBLIPDirect( rSt, aGraf, &aVisArea );
3811                     }
3812                 }
3813             }
3814         }
3815         if ( bGrfRead )
3816         {
3817             // the writer is doing its own cropping, so this part affects only impress and calc,
3818             // unless we're inside a group, in which case writer doesn't crop either
3819             if (( GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_CROP_BITMAPS ) || rObjData.nCalledByGroup != 0 )
3820                 lcl_ApplyCropping( *this, !bool( rObjData.nSpFlags & ShapeFlag::OLEShape ) ? &rSet : nullptr, aGraf );
3821 
3822             if ( IsProperty( DFF_Prop_pictureTransparent ) )
3823             {
3824                 sal_uInt32 nTransColor = GetPropertyValue( DFF_Prop_pictureTransparent, 0 );
3825 
3826                 if ( aGraf.GetType() == GraphicType::Bitmap )
3827                 {
3828                     BitmapEx aBitmapEx( aGraf.GetBitmapEx() );
3829                     aBitmapEx.CombineMaskOr( MSO_CLR_ToColor( nTransColor, DFF_Prop_pictureTransparent ), 9 );
3830                     aGraf = aBitmapEx;
3831                 }
3832             }
3833 
3834             sal_Int32 nContrast = GetPropertyValue( DFF_Prop_pictureContrast, 0x10000 );
3835             /*
3836             0x10000 is msoffice 50%
3837             < 0x10000 is in units of 1/50th of 0x10000 per 1%
3838             > 0x10000 is in units where
3839             a msoffice x% is stored as 50/(100-x) * 0x10000
3840 
3841             plus, a (ui) microsoft % ranges from 0 to 100, OOO
3842             from -100 to 100, so also normalize into that range
3843             */
3844             if ( nContrast > 0x10000 )
3845             {
3846                 double fX = nContrast;
3847                 fX /= 0x10000;
3848                 fX /= 51;   // 50 + 1 to round
3849                 fX = 1/fX;
3850                 nContrast = static_cast<sal_Int32>(fX);
3851                 nContrast -= 100;
3852                 nContrast = -nContrast;
3853                 nContrast = (nContrast-50)*2;
3854             }
3855             else if ( nContrast == 0x10000 )
3856                 nContrast = 0;
3857             else
3858             {
3859                 if (o3tl::checked_multiply<sal_Int32>(nContrast, 101, nContrast))  //100 + 1 to round
3860                 {
3861                     SAL_WARN("filter.ms", "bad Contrast value:" << nContrast);
3862                     nContrast = 0;
3863                 }
3864                 else
3865                 {
3866                     nContrast /= 0x10000;
3867                     nContrast -= 100;
3868                 }
3869             }
3870             sal_Int16   nBrightness     = static_cast<sal_Int16>( static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_pictureBrightness, 0 )) / 327 );
3871             sal_Int32   nGamma          = GetPropertyValue( DFF_Prop_pictureGamma, 0x10000 );
3872             GraphicDrawMode eDrawMode   = GraphicDrawMode::Standard;
3873             switch ( GetPropertyValue( DFF_Prop_pictureActive, 0 ) & 6 )
3874             {
3875                 case 4 : eDrawMode = GraphicDrawMode::Greys; break;
3876                 case 6 : eDrawMode = GraphicDrawMode::Mono; break;
3877                 case 0 :
3878                 {
3879                     //office considers the converted values of (in OOo) 70 to be the
3880                     //"watermark" values, which can vary slightly due to rounding from the
3881                     //above values
3882                     if (( nContrast == -70 ) && ( nBrightness == 70 ))
3883                     {
3884                         nContrast = 0;
3885                         nBrightness = 0;
3886                         eDrawMode = GraphicDrawMode::Watermark;
3887                     };
3888                 }
3889                 break;
3890             }
3891 
3892             if ( nContrast || nBrightness || ( nGamma != 0x10000 ) || ( eDrawMode != GraphicDrawMode::Standard ) )
3893             {
3894                 // MSO uses a different algorithm for contrast+brightness, LO applies contrast before brightness,
3895                 // while MSO apparently applies half of brightness before contrast and half after. So if only
3896                 // contrast or brightness need to be altered, the result is the same, but if both are involved,
3897                 // there's no way to map that, so just force a conversion of the image.
3898                 bool needsConversion = nContrast != 0 && nBrightness != 0;
3899                 if ( !bool(rObjData.nSpFlags & ShapeFlag::OLEShape) && !needsConversion )
3900                 {
3901                     if ( nBrightness )
3902                         rSet.Put( SdrGrafLuminanceItem( nBrightness ) );
3903                     if ( nContrast )
3904                         rSet.Put( SdrGrafContrastItem( static_cast<sal_Int16>(nContrast) ) );
3905                     if ( nGamma != 0x10000 )
3906                         rSet.Put( SdrGrafGamma100Item( nGamma / 655 ) );
3907                     if ( eDrawMode != GraphicDrawMode::Standard )
3908                         rSet.Put( SdrGrafModeItem( eDrawMode ) );
3909                 }
3910                 else
3911                 {
3912                     if ( eDrawMode == GraphicDrawMode::Watermark )
3913                     {
3914                         nContrast = 60;
3915                         nBrightness = 70;
3916                         eDrawMode = GraphicDrawMode::Standard;
3917                     }
3918                     switch ( aGraf.GetType() )
3919                     {
3920                         case GraphicType::Bitmap :
3921                         {
3922                             BitmapEx    aBitmapEx( aGraf.GetBitmapEx() );
3923                             if ( nBrightness || nContrast || ( nGamma != 0x10000 ) )
3924                                 aBitmapEx.Adjust( nBrightness, static_cast<sal_Int16>(nContrast), 0, 0, 0, static_cast<double>(nGamma) / 0x10000, false, true );
3925                             if ( eDrawMode == GraphicDrawMode::Greys )
3926                                 aBitmapEx.Convert( BmpConversion::N8BitGreys );
3927                             else if ( eDrawMode == GraphicDrawMode::Mono )
3928                                 aBitmapEx.Convert( BmpConversion::N1BitThreshold );
3929                             aGraf = aBitmapEx;
3930 
3931                         }
3932                         break;
3933 
3934                         case GraphicType::GdiMetafile :
3935                         {
3936                             GDIMetaFile aGdiMetaFile( aGraf.GetGDIMetaFile() );
3937                             if ( nBrightness || nContrast || ( nGamma != 0x10000 ) )
3938                                 aGdiMetaFile.Adjust( nBrightness, static_cast<sal_Int16>(nContrast), 0, 0, 0, static_cast<double>(nGamma) / 0x10000, false, true );
3939                             if ( eDrawMode == GraphicDrawMode::Greys )
3940                                 aGdiMetaFile.Convert( MtfConversion::N8BitGreys );
3941                             else if ( eDrawMode == GraphicDrawMode::Mono )
3942                                 aGdiMetaFile.Convert( MtfConversion::N1BitThreshold );
3943                             aGraf = aGdiMetaFile;
3944                         }
3945                         break;
3946                         default: break;
3947                     }
3948                 }
3949             }
3950         }
3951 
3952         // should it be an OLE object?
3953         if( bGrfRead && !bLinkGrf && IsProperty( DFF_Prop_pictureId ) )
3954         {
3955             // TODO/LATER: in future probably the correct aspect should be provided here
3956             // #i32596# - pass <nCalledByGroup> to method
3957             pRet = ImportOLE( GetPropertyValue( DFF_Prop_pictureId, 0 ), aGraf, rObjData.aBoundRect, aVisArea, rObjData.nCalledByGroup );
3958         }
3959         if( !pRet )
3960         {
3961             pRet = new SdrGrafObj(*pSdrModel);
3962             if( bGrfRead )
3963                 static_cast<SdrGrafObj*>(pRet)->SetGraphic( aGraf );
3964 
3965             if( bLinkGrf && !bGrfRead )     // sj: #i55484# if the graphic was embedded ( bGrfRead == true ) then
3966             {                               // we do not need to set a link. TODO: not to lose the information where the graphic is linked from
3967                 INetURLObject aAbsURL;
3968                 if ( !INetURLObject( maBaseURL ).GetNewAbsURL( aFileName, &aAbsURL ) )
3969                 {
3970                     OUString aValidURL;
3971                     if( osl::FileBase::getFileURLFromSystemPath( aFileName, aValidURL ) == osl::FileBase::E_None )
3972                         aAbsURL = INetURLObject( aValidURL );
3973                 }
3974                 if( aAbsURL.GetProtocol() != INetProtocol::NotValid )
3975                 {
3976                     aLinkFileName = aAbsURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri );
3977                 }
3978                 else
3979                     aLinkFileName = aFileName;
3980             }
3981         }
3982 
3983         // set the size from BLIP if there is one
3984         if ( bGrfRead && !aVisArea.IsEmpty() )
3985             pRet->SetBLIPSizeRectangle( aVisArea );
3986 
3987         if (pRet->GetName().isEmpty())                   // SJ 22.02.00 : PPT OLE IMPORT:
3988         {                                                // name is already set in ImportOLE !!
3989             // JP 01.12.99: SetName before SetModel - because in the other order the Bug 70098 is active
3990             if ( ( eFlags & mso_blipflagType ) != mso_blipflagComment )
3991             {
3992                 INetURLObject aURL;
3993                 aURL.SetSmartURL( aFileName );
3994                 pRet->SetName( aURL.getBase() );
3995             }
3996             else
3997                 pRet->SetName( aFileName );
3998         }
3999     }
4000     pRet->SetLogicRect( rObjData.aBoundRect );
4001 
4002     if (SdrGrafObj* pGrafObj = dynamic_cast<SdrGrafObj*>(pRet))
4003     {
4004         if( aLinkFileName.getLength() )
4005         {
4006             pGrafObj->SetGraphicLink( aLinkFileName );
4007             Graphic aGraphic(pGrafObj->GetGraphic());
4008             aGraphic.setOriginURL(aLinkFileName);
4009         }
4010 
4011         if ( bLinkGrf && !bGrfRead )
4012         {
4013             Graphic aGraf(pGrafObj->GetGraphic());
4014             lcl_ApplyCropping( *this, &rSet, aGraf );
4015         }
4016     }
4017 
4018     return pRet;
4019 }
4020 
4021 // PptSlidePersistEntry& rPersistEntry, SdPage* pPage
4022 SdrObject* SvxMSDffManager::ImportObj( SvStream& rSt, SvxMSDffClientData& rClientData,
4023     tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect, int nCalledByGroup, sal_Int32* pShapeId )
4024 {
4025     SdrObject* pRet = nullptr;
4026     DffRecordHeader aObjHd;
4027     bool bOk = ReadDffRecordHeader(rSt, aObjHd);
4028     if (bOk && aObjHd.nRecType == DFF_msofbtSpgrContainer)
4029     {
4030         pRet = ImportGroup( aObjHd, rSt, rClientData, rClientRect, rGlobalChildRect, nCalledByGroup, pShapeId );
4031     }
4032     else if (bOk && aObjHd.nRecType == DFF_msofbtSpContainer)
4033     {
4034         pRet = ImportShape( aObjHd, rSt, rClientData, rClientRect, rGlobalChildRect, nCalledByGroup, pShapeId );
4035     }
4036     aObjHd.SeekToBegOfRecord( rSt );    // restore FilePos
4037     return pRet;
4038 }
4039 
4040 SdrObject* SvxMSDffManager::ImportGroup( const DffRecordHeader& rHd, SvStream& rSt, SvxMSDffClientData& rClientData,
4041                                             tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect,
4042                                                 int nCalledByGroup, sal_Int32* pShapeId )
4043 {
4044     SdrObject* pRet = nullptr;
4045 
4046     if( pShapeId )
4047         *pShapeId = 0;
4048 
4049     if (!rHd.SeekToContent(rSt))
4050         return pRet;
4051 
4052     DffRecordHeader aRecHd;     // the first atom has to be the SpContainer for the GroupObject
4053     bool bOk = ReadDffRecordHeader(rSt, aRecHd);
4054     if (bOk && aRecHd.nRecType == DFF_msofbtSpContainer)
4055     {
4056         mnFix16Angle = 0_deg100;
4057         if (!aRecHd.SeekToBegOfRecord(rSt))
4058             return pRet;
4059         pRet = ImportObj( rSt, rClientData, rClientRect, rGlobalChildRect, nCalledByGroup + 1, pShapeId );
4060         if ( pRet )
4061         {
4062             Degree100 nGroupRotateAngle(0);
4063             ShapeFlag nSpFlags = nGroupShapeFlags;
4064             nGroupRotateAngle = mnFix16Angle;
4065 
4066             tools::Rectangle aClientRect( rClientRect );
4067 
4068             tools::Rectangle aGlobalChildRect;
4069             if ( !nCalledByGroup || rGlobalChildRect.IsEmpty() )
4070                 aGlobalChildRect = GetGlobalChildAnchor( rHd, rSt, aClientRect );
4071             else
4072                 aGlobalChildRect = rGlobalChildRect;
4073 
4074             if ( ( nGroupRotateAngle > 4500_deg100 && nGroupRotateAngle <= 13500_deg100 )
4075                 || ( nGroupRotateAngle > 22500_deg100 && nGroupRotateAngle <= 31500_deg100 ) )
4076             {
4077                 sal_Int32 nHalfWidth = ( aClientRect.GetWidth() + 1 ) >> 1;
4078                 sal_Int32 nHalfHeight = ( aClientRect.GetHeight() + 1 ) >> 1;
4079                 Point aTopLeft( aClientRect.Left() + nHalfWidth - nHalfHeight,
4080                                 aClientRect.Top() + nHalfHeight - nHalfWidth );
4081                 const tools::Long nRotatedWidth = aClientRect.GetHeight();
4082                 const tools::Long nRotatedHeight = aClientRect.GetWidth();
4083                 Size aNewSize(nRotatedWidth, nRotatedHeight);
4084                 tools::Rectangle aNewRect( aTopLeft, aNewSize );
4085                 aClientRect = aNewRect;
4086             }
4087 
4088             // now importing the inner objects of the group
4089             if (!aRecHd.SeekToEndOfRecord(rSt))
4090                 return pRet;
4091 
4092             while (rSt.good() && ( rSt.Tell() < rHd.GetRecEndFilePos()))
4093             {
4094                 DffRecordHeader aRecHd2;
4095                 if (!ReadDffRecordHeader(rSt, aRecHd2))
4096                     break;
4097                 if ( aRecHd2.nRecType == DFF_msofbtSpgrContainer )
4098                 {
4099                     tools::Rectangle aGroupClientAnchor, aGroupChildAnchor;
4100                     GetGroupAnchors( aRecHd2, rSt, aGroupClientAnchor, aGroupChildAnchor, aClientRect, aGlobalChildRect );
4101                     if (!aRecHd2.SeekToBegOfRecord(rSt))
4102                         return pRet;
4103                     sal_Int32 nShapeId;
4104                     SdrObject* pTmp = ImportGroup( aRecHd2, rSt, rClientData, aGroupClientAnchor, aGroupChildAnchor, nCalledByGroup + 1, &nShapeId );
4105                     if (pTmp)
4106                     {
4107                         SdrObjGroup* pGroup = dynamic_cast<SdrObjGroup*>(pRet);
4108                         if (pGroup && pGroup->GetSubList())
4109                         {
4110                             pGroup->GetSubList()->NbcInsertObject(pTmp);
4111                             if (nShapeId)
4112                                 insertShapeId(nShapeId, pTmp);
4113                         }
4114                         else
4115                             FreeObj(rClientData, pTmp);
4116                     }
4117                 }
4118                 else if ( aRecHd2.nRecType == DFF_msofbtSpContainer )
4119                 {
4120                     if (!aRecHd2.SeekToBegOfRecord(rSt))
4121                         return pRet;
4122                     sal_Int32 nShapeId;
4123                     SdrObject* pTmp = ImportShape( aRecHd2, rSt, rClientData, aClientRect, aGlobalChildRect, nCalledByGroup + 1, &nShapeId );
4124                     if (pTmp)
4125                     {
4126                         SdrObjGroup* pGroup = dynamic_cast<SdrObjGroup*>(pRet);
4127                         if (pGroup && pGroup->GetSubList())
4128                         {
4129                             pGroup->GetSubList()->NbcInsertObject(pTmp);
4130                             if (nShapeId)
4131                                 insertShapeId(nShapeId, pTmp);
4132                         }
4133                         else
4134                             FreeObj(rClientData, pTmp);
4135                     }
4136                 }
4137                 if (!aRecHd2.SeekToEndOfRecord(rSt))
4138                     return pRet;
4139             }
4140 
4141             if ( nGroupRotateAngle )
4142                 pRet->NbcRotate( aClientRect.Center(), nGroupRotateAngle );
4143             if ( nSpFlags & ShapeFlag::FlipV )
4144             {   // BoundRect in aBoundRect
4145                 Point aLeft( aClientRect.Left(), ( aClientRect.Top() + aClientRect.Bottom() ) >> 1 );
4146                 Point aRight( aLeft.X() + 1000, aLeft.Y() );
4147                 pRet->NbcMirror( aLeft, aRight );
4148             }
4149             if ( nSpFlags & ShapeFlag::FlipH )
4150             {   // BoundRect in aBoundRect
4151                 Point aTop( ( aClientRect.Left() + aClientRect.Right() ) >> 1, aClientRect.Top() );
4152                 Point aBottom( aTop.X(), aTop.Y() + 1000 );
4153                 pRet->NbcMirror( aTop, aBottom );
4154             }
4155         }
4156     }
4157     if (o3tl::make_unsigned(nCalledByGroup) < maPendingGroupData.size())
4158     {
4159         // finalization for this group is pending, do it now
4160         pRet = FinalizeObj(maPendingGroupData.back().first, pRet);
4161         maPendingGroupData.pop_back();
4162     }
4163     return pRet;
4164 }
4165 
4166 SdrObject* SvxMSDffManager::ImportShape( const DffRecordHeader& rHd, SvStream& rSt, SvxMSDffClientData& rClientData,
4167                                             tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect,
4168                                             int nCalledByGroup, sal_Int32* pShapeId )
4169 {
4170     SdrObject* pRet = nullptr;
4171 
4172     if( pShapeId )
4173         *pShapeId = 0;
4174 
4175     if (!rHd.SeekToBegOfRecord(rSt))
4176         return pRet;
4177 
4178     DffObjData aObjData( rHd, rClientRect, nCalledByGroup );
4179 
4180     aObjData.bRotateTextWithShape = ( GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_EXCEL ) == 0;
4181     maShapeRecords.Consume( rSt );
4182     if( maShapeRecords.SeekToContent( rSt,
4183         DFF_msofbtUDefProp ) )
4184     {
4185         sal_uInt32  nBytesLeft = maShapeRecords.Current()->nRecLen;
4186         while( 5 < nBytesLeft )
4187         {
4188             sal_uInt16 nPID(0);
4189             rSt.ReadUInt16(nPID);
4190             if (!rSt.good())
4191                 break;
4192             sal_uInt32 nUDData(0);
4193             rSt.ReadUInt32(nUDData);
4194             if (!rSt.good())
4195                 break;
4196             if (nPID == 447)
4197             {
4198                 mbRotateGranientFillWithAngle = nUDData & 0x20;
4199                 break;
4200             }
4201             nBytesLeft  -= 6;
4202         }
4203     }
4204     aObjData.bShapeType = maShapeRecords.SeekToContent( rSt, DFF_msofbtSp );
4205     if ( aObjData.bShapeType )
4206     {
4207         sal_uInt32 temp;
4208         rSt.ReadUInt32( aObjData.nShapeId )
4209            .ReadUInt32( temp );
4210         aObjData.nSpFlags = ShapeFlag(temp);
4211         aObjData.eShapeType = static_cast<MSO_SPT>(maShapeRecords.Current()->nRecInstance);
4212     }
4213     else
4214     {
4215         aObjData.nShapeId = 0;
4216         aObjData.nSpFlags = ShapeFlag::NONE;
4217         aObjData.eShapeType = mso_sptNil;
4218     }
4219 
4220     if( pShapeId )
4221         *pShapeId = aObjData.nShapeId;
4222 
4223     aObjData.bOpt = maShapeRecords.SeekToContent( rSt, DFF_msofbtOPT, SEEK_FROM_CURRENT_AND_RESTART );
4224     if ( aObjData.bOpt )
4225     {
4226         if (!maShapeRecords.Current()->SeekToBegOfRecord(rSt))
4227             return pRet;
4228 #ifdef DBG_AUTOSHAPE
4229         ReadPropSet( rSt, &rClientData, (sal_uInt32)aObjData.eShapeType );
4230 #else
4231         ReadPropSet( rSt, &rClientData );
4232 #endif
4233     }
4234     else
4235     {
4236         InitializePropSet( DFF_msofbtOPT ); // get the default PropSet
4237         static_cast<DffPropertyReader*>(this)->mnFix16Angle = 0_deg100;
4238     }
4239 
4240     aObjData.bOpt2 = maShapeRecords.SeekToContent( rSt, DFF_msofbtUDefProp, SEEK_FROM_CURRENT_AND_RESTART );
4241     if ( aObjData.bOpt2 )
4242     {
4243         maShapeRecords.Current()->SeekToBegOfRecord( rSt );
4244         pSecPropSet.reset( new DffPropertyReader( *this ) );
4245         pSecPropSet->ReadPropSet( rSt, nullptr );
4246     }
4247 
4248     aObjData.bChildAnchor = maShapeRecords.SeekToContent( rSt, DFF_msofbtChildAnchor, SEEK_FROM_CURRENT_AND_RESTART );
4249     if ( aObjData.bChildAnchor )
4250     {
4251         sal_Int32 l(0), o(0), r(0), u(0);
4252         rSt.ReadInt32( l ).ReadInt32( o ).ReadInt32( r ).ReadInt32( u );
4253         Scale( l );
4254         Scale( o );
4255         Scale( r );
4256         Scale( u );
4257         aObjData.aChildAnchor = tools::Rectangle( l, o, r, u );
4258         sal_Int32 nWidth, nHeight;
4259         if (!rGlobalChildRect.IsEmpty() && !rClientRect.IsEmpty() && rGlobalChildRect.GetWidth() && rGlobalChildRect.GetHeight() &&
4260             !o3tl::checked_sub(r, l, nWidth) && !o3tl::checked_sub(u, o, nHeight))
4261         {
4262             double fXScale = static_cast<double>(rClientRect.GetWidth()) / static_cast<double>(rGlobalChildRect.GetWidth());
4263             double fYScale = static_cast<double>(rClientRect.GetHeight()) / static_cast<double>(rGlobalChildRect.GetHeight());
4264             double fl = ( ( l - rGlobalChildRect.Left() ) * fXScale ) + rClientRect.Left();
4265             double fo = ( ( o - rGlobalChildRect.Top()  ) * fYScale ) + rClientRect.Top();
4266             double fWidth = nWidth * fXScale;
4267             double fHeight = nHeight * fYScale;
4268             aObjData.aChildAnchor = tools::Rectangle( Point( fl, fo ), Size( fWidth + 1, fHeight + 1 ) );
4269         }
4270     }
4271 
4272     aObjData.bClientAnchor = maShapeRecords.SeekToContent( rSt, DFF_msofbtClientAnchor, SEEK_FROM_CURRENT_AND_RESTART );
4273     if ( aObjData.bClientAnchor )
4274         ProcessClientAnchor2( rSt, *maShapeRecords.Current(), aObjData );
4275 
4276     if ( aObjData.bChildAnchor )
4277         aObjData.aBoundRect = aObjData.aChildAnchor;
4278 
4279     if ( aObjData.nSpFlags & ShapeFlag::Background )
4280         aObjData.aBoundRect = tools::Rectangle( Point(), Size( 1, 1 ) );
4281 
4282     tools::Rectangle aTextRect;
4283     if ( !aObjData.aBoundRect.IsEmpty() )
4284     {   // apply rotation to the BoundingBox BEFORE an object has been generated
4285         if( mnFix16Angle )
4286         {
4287             Degree100 nAngle = mnFix16Angle;
4288             if ( ( nAngle > 4500_deg100 && nAngle <= 13500_deg100 ) || ( nAngle > 22500_deg100 && nAngle <= 31500_deg100 ) )
4289             {
4290                 sal_Int32 nHalfWidth = ( aObjData.aBoundRect.GetWidth() + 1 ) >> 1;
4291                 sal_Int32 nHalfHeight = ( aObjData.aBoundRect.GetHeight() + 1 ) >> 1;
4292                 Point aTopLeft( aObjData.aBoundRect.Left() + nHalfWidth - nHalfHeight,
4293                                 aObjData.aBoundRect.Top() + nHalfHeight - nHalfWidth );
4294                 Size aNewSize( aObjData.aBoundRect.GetHeight(), aObjData.aBoundRect.GetWidth() );
4295                 tools::Rectangle aNewRect( aTopLeft, aNewSize );
4296                 aObjData.aBoundRect = aNewRect;
4297             }
4298         }
4299         aTextRect = aObjData.aBoundRect;
4300         bool bGraphic = IsProperty( DFF_Prop_pib ) ||
4301                             IsProperty( DFF_Prop_pibName ) ||
4302                             IsProperty( DFF_Prop_pibFlags );
4303 
4304         if ( aObjData.nSpFlags & ShapeFlag::Group )
4305         {
4306             pRet = new SdrObjGroup(*pSdrModel);
4307             /*  After CWS aw033 has been integrated, an empty group object
4308                 cannot store its resulting bounding rectangle anymore. We have
4309                 to return this rectangle via rClientRect now, but only, if
4310                 caller has not passed an own bounding ractangle. */
4311             if ( rClientRect.IsEmpty() )
4312                  rClientRect = aObjData.aBoundRect;
4313             nGroupShapeFlags = aObjData.nSpFlags;
4314         }
4315         else if ( ( aObjData.eShapeType != mso_sptNil ) || IsProperty( DFF_Prop_pVertices ) || bGraphic )
4316         {
4317             SfxItemSet  aSet( pSdrModel->GetItemPool() );
4318 
4319             bool    bIsConnector = ( ( aObjData.eShapeType >= mso_sptStraightConnector1 ) && ( aObjData.eShapeType <= mso_sptCurvedConnector5 ) );
4320             Degree100   nObjectRotation = mnFix16Angle;
4321             ShapeFlag   nSpFlags = aObjData.nSpFlags;
4322 
4323             if ( bGraphic )
4324             {
4325                 if (!mbSkipImages) {
4326                     pRet = ImportGraphic( rSt, aSet, aObjData );        // SJ: #68396# is no longer true (fixed in ppt2000)
4327                     ApplyAttributes( rSt, aSet, aObjData );
4328                     pRet->SetMergedItemSet(aSet);
4329                 }
4330             }
4331             else if ( aObjData.eShapeType == mso_sptLine && !( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 8 ) )
4332             {
4333                 basegfx::B2DPolygon aPoly;
4334                 aPoly.append(basegfx::B2DPoint(aObjData.aBoundRect.Left(), aObjData.aBoundRect.Top()));
4335                 aPoly.append(basegfx::B2DPoint(aObjData.aBoundRect.Right(), aObjData.aBoundRect.Bottom()));
4336                 pRet = new SdrPathObj(
4337                     *pSdrModel,
4338                     OBJ_LINE,
4339                     basegfx::B2DPolyPolygon(aPoly));
4340                 ApplyAttributes( rSt, aSet, aObjData );
4341                 pRet->SetMergedItemSet(aSet);
4342             }
4343             else
4344             {
4345                 if ( GetCustomShapeContent( aObjData.eShapeType ) || IsProperty( DFF_Prop_pVertices ) )
4346                 {
4347 
4348                     ApplyAttributes( rSt, aSet, aObjData );
4349 
4350                     pRet = new SdrObjCustomShape(*pSdrModel);
4351 
4352                     sal_uInt32 ngtextFStrikethrough = GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 );
4353                     bool bIsFontwork = ( ngtextFStrikethrough & 0x4000 ) != 0;
4354 
4355                     // in case of a FontWork, the text is set by the escher import
4356                     if ( bIsFontwork )
4357                     {
4358                         OUString            aObjectText;
4359                         OUString            aFontName;
4360 
4361                         if ( SeekToContent( DFF_Prop_gtextFont, rSt ) )
4362                         {
4363                             SvxFontItem aLatin(EE_CHAR_FONTINFO), aAsian(EE_CHAR_FONTINFO_CJK), aComplex(EE_CHAR_FONTINFO_CTL);
4364                             GetDefaultFonts( aLatin, aAsian, aComplex );
4365 
4366                             aFontName = MSDFFReadZString( rSt, GetPropertyValue( DFF_Prop_gtextFont, 0 ), true );
4367                             aSet.Put( SvxFontItem( aLatin.GetFamily(), aFontName, aLatin.GetStyleName(),
4368                                         PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, EE_CHAR_FONTINFO ));
4369                             aSet.Put( SvxFontItem( aLatin.GetFamily(), aFontName, aLatin.GetStyleName(),
4370                                         PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, EE_CHAR_FONTINFO_CJK ) );
4371                             aSet.Put( SvxFontItem( aLatin.GetFamily(), aFontName, aLatin.GetStyleName(),
4372                                         PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, EE_CHAR_FONTINFO_CTL ) );
4373                         }
4374 
4375                         // SJ: applying fontattributes for Fontwork :
4376                         if ( IsHardAttribute( DFF_Prop_gtextFItalic ) )
4377                             aSet.Put( SvxPostureItem( ( ngtextFStrikethrough & 0x0010 ) != 0 ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC ) );
4378 
4379                         if ( IsHardAttribute( DFF_Prop_gtextFBold ) )
4380                             aSet.Put( SvxWeightItem( ( ngtextFStrikethrough & 0x0020 ) != 0 ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT ) );
4381 
4382                         // SJ TODO: Vertical Writing is not correct, instead
4383                         // this should be replaced through "CharacterRotation"
4384                         // by 90 degrees, therefore a new Item has to be
4385                         // supported by svx core, api and xml file format
4386                         static_cast<SdrObjCustomShape*>(pRet)->SetVerticalWriting( ( ngtextFStrikethrough & 0x2000 ) != 0 );
4387 
4388                         if ( SeekToContent( DFF_Prop_gtextUNICODE, rSt ) )
4389                         {
4390                             aObjectText = MSDFFReadZString( rSt, GetPropertyValue( DFF_Prop_gtextUNICODE, 0 ), true );
4391                             ReadObjText( aObjectText, pRet );
4392                         }
4393 
4394                         auto eGeoTextAlign = GetPropertyValue(DFF_Prop_gtextAlign, mso_alignTextCenter);
4395                         {
4396                             SdrTextHorzAdjust eHorzAdjust;
4397                             switch( eGeoTextAlign )
4398                             {
4399                                 case mso_alignTextLetterJust :
4400                                 case mso_alignTextWordJust :
4401                                 case mso_alignTextStretch : eHorzAdjust = SDRTEXTHORZADJUST_BLOCK; break;
4402                                 default:
4403                                 case mso_alignTextInvalid :
4404                                 case mso_alignTextCenter : eHorzAdjust = SDRTEXTHORZADJUST_CENTER; break;
4405                                 case mso_alignTextLeft : eHorzAdjust = SDRTEXTHORZADJUST_LEFT; break;
4406                                 case mso_alignTextRight : eHorzAdjust = SDRTEXTHORZADJUST_RIGHT; break;
4407                             }
4408                             aSet.Put( SdrTextHorzAdjustItem( eHorzAdjust ) );
4409 
4410                             drawing::TextFitToSizeType eFTS = drawing::TextFitToSizeType_NONE;
4411                             if ( eGeoTextAlign == mso_alignTextStretch )
4412                                 eFTS = drawing::TextFitToSizeType_ALLLINES;
4413                             aSet.Put( SdrTextFitToSizeTypeItem( eFTS ) );
4414                         }
4415                         if ( IsProperty( DFF_Prop_gtextSpacing ) )
4416                         {
4417                             sal_Int32 nTextWidth = GetPropertyValue( DFF_Prop_gtextSpacing, 1 << 16 ) / 655;
4418                             if ( nTextWidth != 100 )
4419                                 aSet.Put( SvxCharScaleWidthItem( static_cast<sal_uInt16>(nTextWidth), EE_CHAR_FONTWIDTH ) );
4420                         }
4421                         if ( ngtextFStrikethrough & 0x1000 ) // SJ: Font Kerning On ?
4422                             aSet.Put( SvxKerningItem( 1, EE_CHAR_KERNING ) );
4423 
4424                         // #i119496# the resize autoshape to fit text attr of word art in MS PPT is always false
4425                         aSet.Put(makeSdrTextAutoGrowHeightItem(false));
4426                         aSet.Put(makeSdrTextAutoGrowWidthItem(false));
4427 
4428                         bool bWithPadding = !( ngtextFStrikethrough & use_gtextFBestFit
4429                                             && ngtextFStrikethrough & use_gtextFShrinkFit
4430                                             && ngtextFStrikethrough & use_gtextFStretch
4431                                             && ngtextFStrikethrough & gtextFBestFit
4432                                             && ngtextFStrikethrough & gtextFShrinkFit
4433                                             && ngtextFStrikethrough & gtextFStretch );
4434 
4435                         if ( bWithPadding )
4436                         {
4437                             // trim, remove additional space
4438                             VclPtr<VirtualDevice> pDevice = VclPtr<VirtualDevice>::Create();
4439                             vcl::Font aFont = pDevice->GetFont();
4440                             aFont.SetFamilyName( aFontName );
4441                             aFont.SetFontSize( Size( 0, 96 ) );
4442                             pDevice->SetFont( aFont );
4443 
4444                             auto nTextWidth = pDevice->GetTextWidth( aObjectText );
4445                             OUString aObjName = GetPropertyString( DFF_Prop_wzName, rSt );
4446                             if ( nTextWidth && aObjData.eShapeType == mso_sptTextPlainText
4447                                 && aObjName.match( "PowerPlusWaterMarkObject" ) )
4448                             {
4449                                 double fRatio = static_cast<double>(pDevice->GetTextHeight()) / nTextWidth;
4450                                 sal_Int32 nNewHeight = fRatio * aObjData.aBoundRect.getWidth();
4451                                 sal_Int32 nPaddingY = aObjData.aBoundRect.getHeight() - nNewHeight;
4452 
4453                                 if ( nPaddingY > 0 )
4454                                     aObjData.aBoundRect.setHeight( nNewHeight );
4455                             }
4456                         }
4457                     }
4458                     pRet->SetMergedItemSet( aSet );
4459 
4460                     // sj: taking care of rtl, ltr. In case of fontwork mso. seems not to be able to set
4461                     // proper text directions, instead the text default is depending to the string.
4462                     // so we have to calculate the a text direction from string:
4463                     if ( bIsFontwork )
4464                     {
4465                         OutlinerParaObject* pParaObj = static_cast<SdrObjCustomShape*>(pRet)->GetOutlinerParaObject();
4466                         if ( pParaObj )
4467                         {
4468                             SdrOutliner& rOutliner = static_cast<SdrObjCustomShape*>(pRet)->ImpGetDrawOutliner();
4469                             bool bOldUpdateMode = rOutliner.GetUpdateMode();
4470                             rOutliner.SetStyleSheetPool(static_cast< SfxStyleSheetPool* >(pRet->getSdrModelFromSdrObject().GetStyleSheetPool()));
4471                             rOutliner.SetUpdateMode( false );
4472                             rOutliner.SetText( *pParaObj );
4473                             ScopedVclPtrInstance< VirtualDevice > pVirDev(DeviceFormat::BITMASK);
4474                             pVirDev->SetMapMode(MapMode(MapUnit::Map100thMM));
4475                             sal_Int32 i, nParagraphs = rOutliner.GetParagraphCount();
4476                             if ( nParagraphs )
4477                             {
4478                                 bool bCreateNewParaObject = false;
4479                                 for ( i = 0; i < nParagraphs; i++ )
4480                                 {
4481                                     OUString aString(rOutliner.GetText(rOutliner.GetParagraph(i)));
4482                                     bool bIsRTL = pVirDev->GetTextIsRTL(aString, 0, aString.getLength());
4483                                     if ( bIsRTL )
4484                                     {
4485                                         SfxItemSet aSet2( rOutliner.GetParaAttribs( i ) );
4486                                         aSet2.Put( SvxFrameDirectionItem( SvxFrameDirection::Horizontal_RL_TB, EE_PARA_WRITINGDIR ) );
4487                                         rOutliner.SetParaAttribs( i, aSet2 );
4488                                         bCreateNewParaObject = true;
4489                                     }
4490                                 }
4491                                 if  ( bCreateNewParaObject )
4492                                 {
4493                                     std::unique_ptr<OutlinerParaObject> pNewText = rOutliner.CreateParaObject();
4494                                     rOutliner.Init( OutlinerMode::TextObject );
4495                                     static_cast<SdrObjCustomShape*>(pRet)->NbcSetOutlinerParaObject( std::move(pNewText) );
4496                                 }
4497                             }
4498                             rOutliner.Clear();
4499                             rOutliner.SetUpdateMode( bOldUpdateMode );
4500                         }
4501                     }
4502 
4503                     // mso_sptArc special treating
4504                     // tdf#124029: A new custom shape is generated from prototype 'msoArc'. Values, which are
4505                     // read here, are adapted and merged. The shape type is changed, so this code
4506                     // applies only if importing arcs from MS Office.
4507                     if ( aObjData.eShapeType == mso_sptArc )
4508                     {
4509                         const OUString sAdjustmentValues( "AdjustmentValues" );
4510                         const OUString sViewBox( "ViewBox" );
4511                         const OUString sPath( "Path" );
4512                         SdrCustomShapeGeometryItem aGeometryItem( static_cast<SdrObjCustomShape*>(pRet)->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
4513                         PropertyValue aPropVal;
4514 
4515                         // The default arc goes form -90deg to 0deg. Replace general defaults used
4516                         // when read from stream with this specific values.
4517                         double fStartAngle(-90.0);
4518                         double fEndAngle(0.0);
4519                         css::uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > seqAdjustmentValues;
4520                         const uno::Any* pAny = aGeometryItem.GetPropertyValueByName(sAdjustmentValues);
4521                         if (pAny && (*pAny >>= seqAdjustmentValues) && seqAdjustmentValues.getLength() > 1)
4522                         {
4523                             if (seqAdjustmentValues[0].State == css::beans::PropertyState_DEFAULT_VALUE)
4524                             {
4525                                 seqAdjustmentValues[0].Value <<= -90.0;
4526                                 seqAdjustmentValues[0].State = com::sun::star::beans::PropertyState_DIRECT_VALUE;
4527                             }
4528                             if (seqAdjustmentValues[1].State == css::beans::PropertyState_DEFAULT_VALUE)
4529                             {
4530                                 seqAdjustmentValues[1].Value <<= 0.0;
4531                                 seqAdjustmentValues[1].State = com::sun::star::beans::PropertyState_DIRECT_VALUE;
4532                             }
4533                             seqAdjustmentValues[0].Value >>= fStartAngle;
4534                             seqAdjustmentValues[1].Value >>= fEndAngle;
4535                             aPropVal.Name = sAdjustmentValues;
4536                             aPropVal.Value <<= seqAdjustmentValues;
4537                             aGeometryItem.SetPropertyValue(aPropVal);
4538                         }
4539 
4540                         // arc first command is always wr -- clockwise arc
4541                         // the parameters are : (left,top),(right,bottom),start(x,y),end(x,y)
4542                         // The left/top vertex of the frame rectangle of the sector is the origin
4543                         // of the shape internal coordinate system in MS Office. The default arc
4544                         // has an ellipse frame rectangle with LT(-21600,0) and
4545                         // RB(21600,43200) in this coordinate system.
4546                         basegfx::B2DRectangle aEllipseRect_MS(-21600.0, 0.0, 21600.0, 43200.0);
4547                         css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> seqCoordinates;
4548                         pAny = aGeometryItem.GetPropertyValueByName( sPath, "Coordinates" );
4549                         if (pAny && (*pAny >>= seqCoordinates) && (seqCoordinates.getLength() >= 2))
4550                         {
4551                             auto const nL
4552                                 = *o3tl::doAccess<sal_Int32>(seqCoordinates[0].First.Value);
4553                             auto const nT
4554                                 = *o3tl::doAccess<sal_Int32>(seqCoordinates[0].Second.Value);
4555                             auto const nR
4556                                 = *o3tl::doAccess<sal_Int32>(seqCoordinates[1].First.Value);
4557                             auto const nB
4558                                 = *o3tl::doAccess<sal_Int32>(seqCoordinates[1].Second.Value);
4559                             aEllipseRect_MS = basegfx::B2DRectangle(nL, nT, nR, nB);
4560                         }
4561 
4562                         // MS Office uses the pie frame rectangle as reference for outer position
4563                         // and size of the shape and for text in the shape. We can get this rectangle
4564                         // from imported viewBox or from the arc geometry.
4565                         basegfx::B2DRectangle aPieRect_MS(0.0 , 0.0, 21600.0, 21600.0);
4566                         pAny = aGeometryItem.GetPropertyValueByName(sPath,sViewBox);
4567                         css::awt::Rectangle aImportedViewBox;
4568                         if (pAny && (*pAny >>= aImportedViewBox))
4569                         {
4570                             aPieRect_MS = basegfx::B2DRectangle( aImportedViewBox.X,
4571                                                                 aImportedViewBox.Y,
4572                                                       aImportedViewBox.X + aImportedViewBox.Width,
4573                                                       aImportedViewBox.Y + aImportedViewBox.Height);
4574                         }
4575                         else
4576                         {
4577                             double fRadStartAngle(basegfx::deg2rad(NormAngle360(fStartAngle)));
4578                             double fRadEndAngle(basegfx::deg2rad(NormAngle360(fEndAngle)));
4579                             basegfx::B2DPoint aCenter(aEllipseRect_MS.getCenter());
4580                             basegfx::B2DPolygon aTempPie(
4581                                     basegfx::utils::createPolygonFromEllipseSegment(
4582                                         aCenter,
4583                                         aEllipseRect_MS.getWidth() * 0.5,
4584                                         aEllipseRect_MS.getHeight() * 0.5,
4585                                         fRadStartAngle,
4586                                         fRadEndAngle));
4587                             aTempPie.append(aCenter);
4588                             aPieRect_MS = aTempPie.getB2DRange();
4589                         }
4590 
4591                         // MS Office uses for mso_sptArc a frame rectangle (=resize handles)
4592                         // which encloses only the sector, LibreOffice uses for custom shapes as
4593                         // default a frame rectangle, which encloses the entire ellipse. That would
4594                         // result in wrong positions in Writer and Calc, see tdf#124029.
4595                         // We workaround this problem, by setting a suitable viewBox.
4596                         bool bIsImportPPT(GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_PPT);
4597                         if (bIsImportPPT || aPieRect_MS.getWidth() == 0 ||  aPieRect_MS.getHeight() == 0)
4598                         { // clear item, so that default from EnhancedCustomShapeGeometry is used
4599                             aGeometryItem.ClearPropertyValue(sViewBox);
4600                         }
4601                         else
4602                         {
4603                             double fX((aPieRect_MS.getMinX() - aEllipseRect_MS.getMinX()) / 2.0);
4604                             double fY((aPieRect_MS.getMinY() - aEllipseRect_MS.getMinY()) / 2.0);
4605                             css::awt::Rectangle aViewBox_LO; // in LO coordinate system
4606                             aViewBox_LO.X = static_cast<sal_Int32>(fX);
4607                             aViewBox_LO.Y = static_cast<sal_Int32>(fY);
4608                             aViewBox_LO.Width = static_cast<sal_Int32>(aPieRect_MS.getWidth() / 2.0);
4609                             aViewBox_LO.Height = static_cast<sal_Int32>(aPieRect_MS.getHeight() / 2.0);
4610                             aPropVal.Name = sViewBox;
4611                             aPropVal.Value <<= aViewBox_LO;
4612                             aGeometryItem.SetPropertyValue(aPropVal);
4613                         }
4614 
4615                         // aObjData.aBoundRect contains position and size of the sector in (outer)
4616                         // logic coordinates, e.g. for PPT in 1/100 mm, for Word in twips.
4617                         // For Impress the default viewBox is used, so adapt aObjData.aBoundRect.
4618                         tools::Rectangle aOldBoundRect(aObjData.aBoundRect); // backup, needed later on
4619                         if (bIsImportPPT)
4620                         {
4621                             double fLogicXOfs(0.0); // LogicLeft_LO = LogicLeft_MS + fXLogicOfs
4622                             double fLogicYOfs(0.0);
4623                             double fLogicPieWidth(aObjData.aBoundRect.getWidth());
4624                             double fLogicPieHeight(aObjData.aBoundRect.getHeight());
4625                             double fLogicEllipseWidth(0.0); // to be LogicWidth_LO
4626                             double fLogicEllipseHeight(0.0);
4627                             if (aPieRect_MS.getWidth())
4628                             {
4629                                 // fXScale = ratio 'logic length' : 'shape internal length'
4630                                 double fXScale = fLogicPieWidth / aPieRect_MS.getWidth();
4631                                 if (nSpFlags & ShapeFlag::FlipH)
4632                                     fLogicXOfs = (aPieRect_MS.getMaxX() - aEllipseRect_MS.getMaxX()) * fXScale;
4633                                 else
4634                                     fLogicXOfs = (aEllipseRect_MS.getMinX() - aPieRect_MS.getMinX()) * fXScale;
4635                                 fLogicEllipseWidth = aEllipseRect_MS.getWidth() * fXScale;
4636                             }
4637                             if (aPieRect_MS.getHeight())
4638                             {
4639                                 double fYScale = fLogicPieHeight / aPieRect_MS.getHeight();
4640                                 if (nSpFlags & ShapeFlag::FlipV)
4641                                     fLogicYOfs = (aPieRect_MS.getMaxY() - aEllipseRect_MS.getMaxY()) * fYScale;
4642                                 else
4643                                     fLogicYOfs = (aEllipseRect_MS.getMinY() - aPieRect_MS.getMinY()) * fYScale;
4644                                 fLogicEllipseHeight = aEllipseRect_MS.getHeight() * fYScale;
4645                             }
4646                             aObjData.aBoundRect = tools::Rectangle(
4647                                                     Point(aOldBoundRect.Left() + static_cast<sal_Int32>(fLogicXOfs),
4648                                                           aOldBoundRect.Top() + static_cast<sal_Int32>(fLogicYOfs)),
4649                                                     Size(static_cast<sal_Int32>(fLogicEllipseWidth),
4650                                                          static_cast<sal_Int32>(fLogicEllipseHeight)));
4651                         }
4652                         // else nothing to do. aObjData.aBoundRect corresponds to changed viewBox.
4653 
4654                         // creating the text frame -> scaling into (0,0),(21600,21600) destination coordinate system
4655                         double fTextFrameScaleX = 0.0;
4656                         double fTextFrameScaleY = 0.0;
4657                         if (aEllipseRect_MS.getWidth())
4658                             fTextFrameScaleX = 21600.0 / aEllipseRect_MS.getWidth();
4659                         if (aEllipseRect_MS.getHeight())
4660                             fTextFrameScaleY = 21600.0 / aEllipseRect_MS.getHeight();
4661 
4662                         sal_Int32 nLeft  = static_cast<sal_Int32>((aPieRect_MS.getMinX() - aEllipseRect_MS.getMinX()) * fTextFrameScaleX );
4663                         sal_Int32 nTop   = static_cast<sal_Int32>((aPieRect_MS.getMinY() - aEllipseRect_MS.getMinY()) * fTextFrameScaleY );
4664                         sal_Int32 nRight = static_cast<sal_Int32>((aPieRect_MS.getMaxX() - aEllipseRect_MS.getMinX()) * fTextFrameScaleX );
4665                         sal_Int32 nBottom= static_cast<sal_Int32>((aPieRect_MS.getMaxY() - aEllipseRect_MS.getMinY()) * fTextFrameScaleY );
4666                         css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aTextFrame( 1 );
4667                         EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aTextFrame[ 0 ].TopLeft.First,     nLeft );
4668                         EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aTextFrame[ 0 ].TopLeft.Second,    nTop );
4669                         EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aTextFrame[ 0 ].BottomRight.First, nRight );
4670                         EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( aTextFrame[ 0 ].BottomRight.Second,nBottom );
4671                         PropertyValue aProp;
4672                         aProp.Name = "TextFrames";
4673                         aProp.Value <<= aTextFrame;
4674                         aGeometryItem.SetPropertyValue( sPath, aProp );
4675 
4676                         // sj: taking care of the different rotation points, since the new arc is having a bigger snaprect
4677                         if ( mnFix16Angle )
4678                         {
4679                             Degree100 nAngle = mnFix16Angle;
4680                             if ( nSpFlags & ShapeFlag::FlipH )
4681                                 nAngle = 36000_deg100 - nAngle;
4682                             if ( nSpFlags & ShapeFlag::FlipV )
4683                                 nAngle = -nAngle;
4684                             double a = nAngle.get() * F_PI18000;
4685                             double ss = sin( a );
4686                             double cc = cos( a );
4687                             Point aP1( aOldBoundRect.TopLeft() );
4688                             Point aC1( aObjData.aBoundRect.Center() );
4689                             Point aP2( aOldBoundRect.TopLeft() );
4690                             Point aC2( aOldBoundRect.Center() );
4691                             RotatePoint( aP1, aC1, ss, cc );
4692                             RotatePoint( aP2, aC2, ss, cc );
4693                             aObjData.aBoundRect.Move( aP2.X() - aP1.X(), aP2.Y() - aP1.Y() );
4694                         }
4695 
4696                         // clearing items, so MergeDefaultAttributes will set the corresponding
4697                         // defaults from EnhancedCustomShapeGeometry
4698                         aGeometryItem.ClearPropertyValue( "Handles" );
4699                         aGeometryItem.ClearPropertyValue( "Equations" );
4700                         aGeometryItem.ClearPropertyValue( sPath );
4701 
4702                         static_cast<SdrObjCustomShape*>(pRet)->SetMergedItem( aGeometryItem );
4703                         static_cast<SdrObjCustomShape*>(pRet)->MergeDefaultAttributes();
4704 
4705                         // now setting a new name, so the above correction is only done once when importing from ms
4706                         SdrCustomShapeGeometryItem aGeoName( static_cast<SdrObjCustomShape*>(pRet)->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
4707                         aPropVal.Name = "Type";
4708                         aPropVal.Value <<= OUString( "mso-spt100" );
4709                         aGeoName.SetPropertyValue( aPropVal );
4710                         static_cast<SdrObjCustomShape*>(pRet)->SetMergedItem( aGeoName );
4711                     }
4712                     else
4713                         static_cast<SdrObjCustomShape*>(pRet)->MergeDefaultAttributes();
4714 
4715                     pRet->SetSnapRect( aObjData.aBoundRect );
4716                     EnhancedCustomShape2d aCustomShape2d(static_cast<SdrObjCustomShape&>(*pRet));
4717                     aTextRect = aCustomShape2d.GetTextRect();
4718 
4719                     if( bIsConnector )
4720                     {
4721                         if( nObjectRotation )
4722                             pRet->NbcRotate( aObjData.aBoundRect.Center(), nObjectRotation );
4723                         // mirrored horizontally?
4724                         if ( nSpFlags & ShapeFlag::FlipH )
4725                         {
4726                             tools::Rectangle aBndRect( pRet->GetSnapRect() );
4727                             Point aTop( ( aBndRect.Left() + aBndRect.Right() ) >> 1, aBndRect.Top() );
4728                             Point aBottom( aTop.X(), aTop.Y() + 1000 );
4729                             pRet->NbcMirror( aTop, aBottom );
4730                         }
4731                         // mirrored vertically?
4732                         if ( nSpFlags & ShapeFlag::FlipV )
4733                         {
4734                             tools::Rectangle aBndRect( pRet->GetSnapRect() );
4735                             Point aLeft( aBndRect.Left(), ( aBndRect.Top() + aBndRect.Bottom() ) >> 1 );
4736                             Point aRight( aLeft.X() + 1000, aLeft.Y() );
4737                             pRet->NbcMirror( aLeft, aRight );
4738                         }
4739                         basegfx::B2DPolyPolygon aPoly( static_cast<SdrObjCustomShape*>(pRet)->GetLineGeometry( true ) );
4740                         SdrObject::Free( pRet );
4741 
4742                         pRet = new SdrEdgeObj(*pSdrModel);
4743                         ApplyAttributes( rSt, aSet, aObjData );
4744                         pRet->SetLogicRect( aObjData.aBoundRect );
4745                         pRet->SetMergedItemSet(aSet);
4746 
4747                         // connectors
4748                         auto eConnectorStyle = GetPropertyValue(DFF_Prop_cxstyle, mso_cxstyleStraight);
4749 
4750                         static_cast<SdrEdgeObj*>(pRet)->ConnectToNode(true, nullptr);
4751                         static_cast<SdrEdgeObj*>(pRet)->ConnectToNode(false, nullptr);
4752 
4753                         Point aPoint1( aObjData.aBoundRect.TopLeft() );
4754                         Point aPoint2( aObjData.aBoundRect.BottomRight() );
4755 
4756                         // pay attention to the rotations
4757                         if ( nObjectRotation )
4758                         {
4759                             double a = nObjectRotation.get() * F_PI18000;
4760                             Point aCenter( aObjData.aBoundRect.Center() );
4761                             double ss = sin(a);
4762                             double cc = cos(a);
4763 
4764                             RotatePoint(aPoint1, aCenter, ss, cc);
4765                             RotatePoint(aPoint2, aCenter, ss, cc);
4766 
4767                             // #i120437# reset rotation, it is part of the path and shall not be applied again
4768                             nObjectRotation = 0_deg100;
4769                         }
4770 
4771                         // rotate/mirror line within the area as we need it
4772                         if ( nSpFlags & ShapeFlag::FlipH )
4773                         {
4774                             sal_Int32 n = aPoint1.X();
4775                             aPoint1.setX( aPoint2.X() );
4776                             aPoint2.setX( n );
4777 
4778                             // #i120437# reset hor flip
4779                             nSpFlags &= ~ShapeFlag::FlipH;
4780                         }
4781                         if ( nSpFlags & ShapeFlag::FlipV )
4782                         {
4783                             sal_Int32 n = aPoint1.Y();
4784                             aPoint1.setY( aPoint2.Y() );
4785                             aPoint2.setY( n );
4786 
4787                             // #i120437# reset ver flip
4788                             nSpFlags &= ~ShapeFlag::FlipV;
4789                         }
4790 
4791                         pRet->NbcSetPoint(aPoint1, 0); // start point
4792                         pRet->NbcSetPoint(aPoint2, 1); // endpoint
4793 
4794                         sal_Int32 n1HorzDist, n1VertDist, n2HorzDist, n2VertDist;
4795                         n1HorzDist = n1VertDist = n2HorzDist = n2VertDist = 0;
4796                         switch( eConnectorStyle )
4797                         {
4798                             case mso_cxstyleBent:
4799                             {
4800                                 aSet.Put( SdrEdgeKindItem( SdrEdgeKind::OrthoLines ) );
4801                                 n1HorzDist = n1VertDist = n2HorzDist = n2VertDist = 630;
4802                             }
4803                             break;
4804                             case mso_cxstyleCurved:
4805                                 aSet.Put( SdrEdgeKindItem( SdrEdgeKind::Bezier ) );
4806                             break;
4807                             default: // mso_cxstyleStraight || mso_cxstyleNone
4808                                 aSet.Put( SdrEdgeKindItem( SdrEdgeKind::OneLine ) );
4809                             break;
4810                         }
4811                         aSet.Put( SdrEdgeNode1HorzDistItem( n1HorzDist ) );
4812                         aSet.Put( SdrEdgeNode1VertDistItem( n1VertDist ) );
4813                         aSet.Put( SdrEdgeNode2HorzDistItem( n2HorzDist ) );
4814                         aSet.Put( SdrEdgeNode2VertDistItem( n2VertDist ) );
4815 
4816                         static_cast<SdrEdgeObj*>(pRet)->SetEdgeTrackPath( aPoly );
4817                         pRet->SetMergedItemSet( aSet );
4818                     }
4819                     if ( aObjData.eShapeType == mso_sptLine )
4820                     {
4821                         pRet->SetMergedItemSet(aSet);
4822                         static_cast<SdrObjCustomShape*>(pRet)->MergeDefaultAttributes();
4823                     }
4824                 }
4825             }
4826 
4827             if ( pRet )
4828             {
4829                 if( nObjectRotation )
4830                     pRet->NbcRotate( aObjData.aBoundRect.Center(), nObjectRotation );
4831                 // mirrored horizontally?
4832                 if ( nSpFlags & ShapeFlag::FlipH )
4833                 {
4834                     tools::Rectangle aBndRect( pRet->GetSnapRect() );
4835                     Point aTop( ( aBndRect.Left() + aBndRect.Right() ) >> 1, aBndRect.Top() );
4836                     Point aBottom( aTop.X(), aTop.Y() + 1000 );
4837                     pRet->NbcMirror( aTop, aBottom );
4838                 }
4839                 // mirrored vertically?
4840                 if ( nSpFlags & ShapeFlag::FlipV )
4841                 {
4842                     tools::Rectangle aBndRect( pRet->GetSnapRect() );
4843                     Point aLeft( aBndRect.Left(), ( aBndRect.Top() + aBndRect.Bottom() ) >> 1 );
4844                     Point aRight( aLeft.X() + 1000, aLeft.Y() );
4845                     pRet->NbcMirror( aLeft, aRight );
4846                 }
4847             }
4848         }
4849     }
4850 
4851     // #i51348# #118052# name of the shape
4852     if( pRet )
4853     {
4854         OUString aObjName = GetPropertyString( DFF_Prop_wzName, rSt );
4855         if( !aObjName.isEmpty() )
4856             pRet->SetName( aObjName );
4857     }
4858 
4859     pRet =
4860         ProcessObj( rSt, aObjData, rClientData, aTextRect, pRet);
4861 
4862     if ( pRet )
4863     {
4864         sal_Int32 nGroupProperties( GetPropertyValue( DFF_Prop_fPrint, 0 ) );
4865         const bool bVisible = ( ( nGroupProperties & 2 ) == 0 );
4866         pRet->SetVisible( bVisible );
4867         // In Excel hidden means not printed
4868         if ( !bVisible )
4869         {
4870             pRet->SetPrintable( false );
4871         }
4872         else
4873         {
4874             // This property isn't used in Excel anymore, leaving it for legacy reasons
4875             pRet->SetPrintable( ( nGroupProperties & 1 ) != 0 );
4876         }
4877     }
4878 
4879     //Import alt text as description
4880     if ( pRet && SeekToContent( DFF_Prop_wzDescription, rSt ) )
4881     {
4882         OUString aAltText = MSDFFReadZString(rSt, GetPropertyValue(DFF_Prop_wzDescription, 0), true);
4883         pRet->SetDescription( aAltText );
4884     }
4885 
4886     // If this shape opens a new group, push back its object data because
4887     // finalization will be called when nested objects have been imported;
4888     // otherwise, just finalize here
4889     if (o3tl::make_unsigned(nCalledByGroup) > maPendingGroupData.size())
4890     {
4891         auto xHdClone = std::make_shared<DffRecordHeader>(aObjData.rSpHd);
4892         maPendingGroupData.emplace_back(DffObjData(xHdClone, aObjData), xHdClone );
4893     }
4894     else
4895     {
4896         pRet = FinalizeObj(aObjData, pRet);
4897     }
4898     return pRet;
4899 }
4900 
4901 tools::Rectangle SvxMSDffManager::GetGlobalChildAnchor( const DffRecordHeader& rHd, SvStream& rSt, tools::Rectangle& aClientRect )
4902 {
4903     tools::Rectangle aChildAnchor;
4904     if (!rHd.SeekToContent(rSt))
4905         return aChildAnchor;
4906 
4907     bool bIsClientRectRead = false;
4908     while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < rHd.GetRecEndFilePos() ) )
4909     {
4910         DffRecordHeader aShapeHd;
4911         if (!ReadDffRecordHeader(rSt, aShapeHd))
4912             break;
4913         if ( ( aShapeHd.nRecType == DFF_msofbtSpContainer ) ||
4914                 ( aShapeHd.nRecType == DFF_msofbtSpgrContainer ) )
4915         {
4916             DffRecordHeader aShapeHd2( aShapeHd );
4917             if ( aShapeHd.nRecType == DFF_msofbtSpgrContainer )
4918                 ReadDffRecordHeader( rSt, aShapeHd2 );
4919             while (rSt.good() && rSt.Tell() < aShapeHd2.GetRecEndFilePos())
4920             {
4921                 DffRecordHeader aShapeAtom;
4922                 if (!ReadDffRecordHeader(rSt, aShapeAtom))
4923                     break;
4924 
4925                 if ( aShapeAtom.nRecType == DFF_msofbtClientAnchor )
4926                 {
4927                     if ( GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_PPT )
4928                     {
4929                         sal_Int32 l(0), t(0), r(0), b(0);
4930                         if ( aShapeAtom.nRecLen == 16 )
4931                         {
4932                             rSt.ReadInt32( l ).ReadInt32( t ).ReadInt32( r ).ReadInt32( b );
4933                         }
4934                         else
4935                         {
4936                             sal_Int16 ls(0), ts(0), rs(0), bs(0);
4937                             rSt.ReadInt16( ts ).ReadInt16( ls ).ReadInt16( rs ).ReadInt16( bs ); // the order of coordinates is a bit strange...
4938                             l = ls;
4939                             t = ts;
4940                             r = rs;
4941                             b = bs;
4942                         }
4943                         Scale( l );
4944                         Scale( t );
4945                         Scale( r );
4946                         Scale( b );
4947                         if ( bIsClientRectRead )
4948                         {
4949                             tools::Rectangle aChild( l, t, r, b );
4950                             aChildAnchor.Union( aChild );
4951                         }
4952                         else
4953                         {
4954                             aClientRect = tools::Rectangle( l, t, r, b );
4955                             bIsClientRectRead = true;
4956                         }
4957                     }
4958                     break;
4959                 }
4960                 else if ( aShapeAtom.nRecType == DFF_msofbtChildAnchor )
4961                 {
4962                     sal_Int32 l(0), o(0), r(0), u(0);
4963                     rSt.ReadInt32( l ).ReadInt32( o ).ReadInt32( r ).ReadInt32( u );
4964                     Scale( l );
4965                     Scale( o );
4966                     Scale( r );
4967                     Scale( u );
4968                     tools::Rectangle aChild( l, o, r, u );
4969                     aChildAnchor.Union( aChild );
4970                     break;
4971                 }
4972                 if (!aShapeAtom.SeekToEndOfRecord(rSt))
4973                     break;
4974             }
4975         }
4976         if (!aShapeHd.SeekToEndOfRecord(rSt))
4977             break;
4978     }
4979     return aChildAnchor;
4980 }
4981 
4982 void SvxMSDffManager::GetGroupAnchors( const DffRecordHeader& rHd, SvStream& rSt,
4983                             tools::Rectangle& rGroupClientAnchor, tools::Rectangle& rGroupChildAnchor,
4984                                 const tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect )
4985 {
4986     if (!rHd.SeekToContent(rSt))
4987         return;
4988 
4989     bool bFirst = true;
4990     DffRecordHeader aShapeHd;
4991     while (rSt.good() && rSt.Tell() < rHd.GetRecEndFilePos())
4992     {
4993         if (!ReadDffRecordHeader(rSt, aShapeHd))
4994             break;
4995         if ( ( aShapeHd.nRecType == DFF_msofbtSpContainer ) ||
4996                 ( aShapeHd.nRecType == DFF_msofbtSpgrContainer ) )
4997         {
4998             DffRecordHeader aShapeHd2( aShapeHd );
4999             if ( aShapeHd.nRecType == DFF_msofbtSpgrContainer )
5000                 ReadDffRecordHeader( rSt, aShapeHd2 );
5001             while (rSt.good() && rSt.Tell() < aShapeHd2.GetRecEndFilePos())
5002             {
5003                 DffRecordHeader aShapeAtom;
5004                 if (!ReadDffRecordHeader(rSt, aShapeAtom))
5005                     break;
5006                 if ( aShapeAtom.nRecType == DFF_msofbtChildAnchor )
5007                 {
5008                     sal_Int32 l(0), o(0), r(0), u(0);
5009                     rSt.ReadInt32( l ).ReadInt32( o ).ReadInt32( r ).ReadInt32( u );
5010                     Scale( l );
5011                     Scale( o );
5012                     Scale( r );
5013                     Scale( u );
5014                     tools::Rectangle aChild( l, o, r, u );
5015 
5016                     if ( bFirst )
5017                     {
5018                         if ( !rGlobalChildRect.IsEmpty() && !rClientRect.IsEmpty() && rGlobalChildRect.GetWidth() && rGlobalChildRect.GetHeight() )
5019                         {
5020                             double fWidth = o3tl::saturating_sub(r, l);
5021                             double fHeight= o3tl::saturating_sub(u, o);
5022                             double fXScale = static_cast<double>(rClientRect.GetWidth()) / static_cast<double>(rGlobalChildRect.GetWidth());
5023                             double fYScale = static_cast<double>(rClientRect.GetHeight()) / static_cast<double>(rGlobalChildRect.GetHeight());
5024                             double fl = ( ( l - rGlobalChildRect.Left() ) * fXScale ) + rClientRect.Left();
5025                             double fo = ( ( o - rGlobalChildRect.Top()  ) * fYScale ) + rClientRect.Top();
5026                             fWidth *= fXScale;
5027                             fHeight *= fYScale;
5028                             rGroupClientAnchor = tools::Rectangle( Point( static_cast<sal_Int32>(fl), static_cast<sal_Int32>(fo) ), Size( static_cast<sal_Int32>( fWidth + 1 ), static_cast<sal_Int32>( fHeight + 1 ) ) );
5029                         }
5030                         bFirst = false;
5031                     }
5032                     else
5033                         rGroupChildAnchor.Union( aChild );
5034                     break;
5035                 }
5036                 if (!aShapeAtom.SeekToEndOfRecord(rSt))
5037                     break;
5038             }
5039         }
5040         if (!aShapeHd.SeekToEndOfRecord(rSt))
5041             break;
5042     }
5043 }
5044 
5045 SvxMSDffImportRec* SvxMSDffImportData::find(const SdrObject* pObj)
5046 {
5047     auto it = m_ObjToRecMap.find(pObj);
5048     if (it != m_ObjToRecMap.end())
5049         return it->second;
5050     return nullptr;
5051 }
5052 
5053 void SvxMSDffImportData::insert(std::unique_ptr<SvxMSDffImportRec> pImpRec)
5054 {
5055     auto aRet = m_Records.insert(std::move(pImpRec));
5056     bool bSuccess = aRet.second;
5057     if (bSuccess)
5058     {
5059         SvxMSDffImportRec* pRec = aRet.first->get();
5060         m_ObjToRecMap[pRec->pObj] = pRec;
5061     }
5062 }
5063 
5064 void SvxMSDffImportData::NotifyFreeObj(SdrObject* pObj)
5065 {
5066     if (SvxMSDffImportRec* pRecord = find(pObj))
5067     {
5068         m_ObjToRecMap.erase(pObj);
5069         pRecord->pObj = nullptr;
5070     }
5071 }
5072 
5073 void SvxMSDffManager::NotifyFreeObj(SvxMSDffClientData& rData, SdrObject* pObj)
5074 {
5075     if (SdrObjGroup* pGroup = dynamic_cast<SdrObjGroup*>(pObj))
5076     {
5077         SdrObjList* pSubList = pGroup->GetSubList();
5078         size_t nObjCount = pSubList->GetObjCount();
5079         for (size_t i = 0; i < nObjCount; ++i)
5080             NotifyFreeObj(rData, pSubList->GetObj(i));
5081     }
5082 
5083     rData.NotifyFreeObj(pObj);
5084 }
5085 
5086 void SvxMSDffManager::FreeObj(SvxMSDffClientData& rData, SdrObject* pObj)
5087 {
5088     NotifyFreeObj(rData, pObj);
5089     SdrObject::Free(pObj);
5090 }
5091 
5092 SdrObject* SvxMSDffManager::ProcessObj(SvStream& rSt,
5093                                        DffObjData& rObjData,
5094                                        SvxMSDffClientData& rData,
5095                                        tools::Rectangle& rTextRect,
5096                                        SdrObject* pObj
5097                                        )
5098 {
5099     if( !rTextRect.IsEmpty() )
5100     {
5101         SvxMSDffImportData& rImportData = static_cast<SvxMSDffImportData&>(rData);
5102         SvxMSDffImportRec* pImpRec = new SvxMSDffImportRec;
5103         bool bDeleteImpRec = true;
5104         SvxMSDffImportRec* pTextImpRec = pImpRec;
5105         bool bDeleteTextImpRec = false;
5106 
5107         // fill Import Record with data
5108         pImpRec->nShapeId   = rObjData.nShapeId;
5109         pImpRec->eShapeType = rObjData.eShapeType;
5110 
5111         auto eWrapMode = GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare);
5112         rObjData.bClientAnchor = maShapeRecords.SeekToContent( rSt,
5113                                             DFF_msofbtClientAnchor,
5114                                             SEEK_FROM_CURRENT_AND_RESTART );
5115         if( rObjData.bClientAnchor )
5116             ProcessClientAnchor( rSt,
5117                     maShapeRecords.Current()->nRecLen,
5118                     pImpRec->pClientAnchorBuffer, pImpRec->nClientAnchorLen );
5119 
5120         rObjData.bClientData = maShapeRecords.SeekToContent( rSt,
5121                                             DFF_msofbtClientData,
5122                                             SEEK_FROM_CURRENT_AND_RESTART );
5123         if( rObjData.bClientData )
5124             ProcessClientData( rSt,
5125                     maShapeRecords.Current()->nRecLen,
5126                     pImpRec->pClientDataBuffer, pImpRec->nClientDataLen );
5127 
5128 
5129         // process user (== Winword) defined parameters in 0xF122 record
5130         if(    maShapeRecords.SeekToContent( rSt,
5131                                              DFF_msofbtUDefProp,
5132                                              SEEK_FROM_CURRENT_AND_RESTART )
5133             && maShapeRecords.Current()->nRecLen )
5134         {
5135             sal_uInt32  nBytesLeft = maShapeRecords.Current()->nRecLen;
5136             while( 5 < nBytesLeft )
5137             {
5138                 sal_uInt16 nPID(0);
5139                 rSt.ReadUInt16(nPID);
5140                 if (!rSt.good())
5141                     break;
5142                 sal_uInt32 nUDData(0);
5143                 rSt.ReadUInt32(nUDData);
5144                 switch (nPID)
5145                 {
5146                     case 0x038F: pImpRec->nXAlign = nUDData; break;
5147                     case 0x0390:
5148                         pImpRec->nXRelTo = nUDData;
5149                         break;
5150                     case 0x0391: pImpRec->nYAlign = nUDData; break;
5151                     case 0x0392:
5152                         pImpRec->nYRelTo = nUDData;
5153                         break;
5154                     case 0x03BF: pImpRec->nLayoutInTableCell = nUDData; break;
5155                     case 0x0393:
5156                     // This seems to correspond to o:hrpct from .docx (even including
5157                     // the difference that it's in 0.1% even though the .docx spec
5158                     // says it's in 1%).
5159                         pImpRec->relativeHorizontalWidth = nUDData;
5160                         break;
5161                     case 0x0394:
5162                     // And this is really just a guess, but a mere presence of this
5163                     // flag makes a horizontal rule be as wide as the page (unless
5164                     // overridden by something), so it probably matches o:hr from .docx.
5165                         pImpRec->isHorizontalRule = true;
5166                         break;
5167                 }
5168                 if (!rSt.good())
5169                     break;
5170                 nBytesLeft  -= 6;
5171             }
5172         }
5173 
5174         //  text frame, also Title or Outline
5175         SdrObject*  pOrgObj  = pObj;
5176         SdrRectObj* pTextObj = nullptr;
5177         sal_uInt32 nTextId = GetPropertyValue( DFF_Prop_lTxid, 0 );
5178         if( nTextId )
5179         {
5180             SfxItemSet aSet( pSdrModel->GetItemPool() );
5181 
5182             //Originally anything that as a mso_sptTextBox was created as a
5183             //textbox, this was changed for #88277# to be created as a simple
5184             //rect to keep impress happy. For the rest of us we'd like to turn
5185             //it back into a textbox again.
5186             bool bTextFrame = (pImpRec->eShapeType == mso_sptTextBox);
5187             if (!bTextFrame)
5188             {
5189                 //Either
5190                 //a) it's a simple text object or
5191                 //b) it's a rectangle with text and square wrapping.
5192                 bTextFrame =
5193                 (
5194                     (pImpRec->eShapeType == mso_sptTextSimple) ||
5195                     (
5196                         (pImpRec->eShapeType == mso_sptRectangle)
5197                         && (eWrapMode == mso_wrapSquare)
5198                         && ShapeHasText(pImpRec->nShapeId, rObjData.rSpHd.GetRecBegFilePos() )
5199                     )
5200                 );
5201             }
5202 
5203             if (bTextFrame)
5204             {
5205                 SdrObject::Free( pObj );
5206                 pObj = pOrgObj = nullptr;
5207             }
5208 
5209             // Distance of Textbox to its surrounding Customshape
5210             sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 91440L);
5211             sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 91440L );
5212             sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 45720L  );
5213             sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 45720L );
5214 
5215             ScaleEmu( nTextLeft );
5216             ScaleEmu( nTextRight );
5217             ScaleEmu( nTextTop );
5218             ScaleEmu( nTextBottom );
5219 
5220             Degree100 nTextRotationAngle(0);
5221             bool bVerticalText = false;
5222             if ( IsProperty( DFF_Prop_txflTextFlow ) )
5223             {
5224                 auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF;
5225                 switch( eTextFlow )
5226                 {
5227                     case mso_txflBtoT:
5228                         nTextRotationAngle = 9000_deg100;
5229                     break;
5230                     case mso_txflVertN:
5231                     case mso_txflTtoBN:
5232                         nTextRotationAngle = 27000_deg100;
5233                         break;
5234                     case mso_txflTtoBA:
5235                         bVerticalText = true;
5236                     break;
5237                     case mso_txflHorzA:
5238                         bVerticalText = true;
5239                         nTextRotationAngle = 9000_deg100;
5240                     break;
5241                     case mso_txflHorzN:
5242                     default :
5243                         break;
5244                 }
5245             }
5246 
5247             if (nTextRotationAngle)
5248             {
5249                 switch (nTextRotationAngle.get())
5250                 {
5251                     case 9000:
5252                         {
5253                             tools::Long nWidth = rTextRect.GetWidth();
5254                             rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() );
5255                             rTextRect.SetBottom( rTextRect.Top() + nWidth );
5256 
5257                             sal_Int32 nOldTextLeft = nTextLeft;
5258                             sal_Int32 nOldTextRight = nTextRight;
5259                             sal_Int32 nOldTextTop = nTextTop;
5260                             sal_Int32 nOldTextBottom = nTextBottom;
5261 
5262                             nTextLeft = nOldTextBottom;
5263                             nTextRight = nOldTextTop;
5264                             nTextTop = nOldTextLeft;
5265                             nTextBottom = nOldTextRight;
5266                         }
5267                         break;
5268                     case 27000:
5269                         {
5270                             tools::Long nWidth = rTextRect.GetWidth();
5271                             rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() );
5272                             rTextRect.SetBottom( rTextRect.Top() + nWidth );
5273 
5274                             sal_Int32 nOldTextLeft = nTextLeft;
5275                             sal_Int32 nOldTextRight = nTextRight;
5276                             sal_Int32 nOldTextTop = nTextTop;
5277                             sal_Int32 nOldTextBottom = nTextBottom;
5278 
5279                             nTextLeft = nOldTextTop;
5280                             nTextRight = nOldTextBottom;
5281                             nTextTop = nOldTextRight;
5282                             nTextBottom = nOldTextLeft;
5283                         }
5284                         break;
5285                 }
5286             }
5287 
5288             pTextObj = new SdrRectObj(
5289                 *pSdrModel,
5290                 OBJ_TEXT,
5291                 rTextRect);
5292             pTextImpRec = new SvxMSDffImportRec(*pImpRec);
5293             bDeleteTextImpRec = true;
5294 
5295             // the vertical paragraph indents are part of the BoundRect,
5296             // here we 'remove' them by calculating
5297             tools::Rectangle aNewRect(rTextRect);
5298             aNewRect.AdjustBottom( -(nTextTop + nTextBottom) );
5299             aNewRect.AdjustRight( -(nTextLeft + nTextRight) );
5300 
5301             // Only if it's a simple textbox may Writer replace
5302             // the object with a frame, otherwise
5303             if( bTextFrame )
5304             {
5305                 auto const pTmpRec = std::make_shared<SvxMSDffShapeInfo>(0, pImpRec->nShapeId);
5306 
5307                 SvxMSDffShapeInfos_ById::const_iterator const it =
5308                     m_xShapeInfosById->find(pTmpRec);
5309                 if (it != m_xShapeInfosById->end())
5310                 {
5311                     SvxMSDffShapeInfo& rInfo = **it;
5312                     pTextImpRec->bReplaceByFly   = rInfo.bReplaceByFly;
5313                 }
5314             }
5315 
5316             if( !pObj )
5317                 ApplyAttributes( rSt, aSet, rObjData );
5318 
5319             bool bFitText = false;
5320             if (GetPropertyValue(DFF_Prop_FitTextToShape, 0) & 2)
5321             {
5322                 aSet.Put( makeSdrTextAutoGrowHeightItem( true ) );
5323                 aSet.Put( makeSdrTextMinFrameHeightItem(
5324                     aNewRect.Bottom() - aNewRect.Top() ) );
5325                 aSet.Put( makeSdrTextMinFrameWidthItem(
5326                     aNewRect.Right() - aNewRect.Left() ) );
5327                 bFitText = true;
5328             }
5329             else
5330             {
5331                 aSet.Put( makeSdrTextAutoGrowHeightItem( false ) );
5332                 aSet.Put( makeSdrTextAutoGrowWidthItem( false ) );
5333             }
5334 
5335             switch (GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare))
5336             {
5337                 case mso_wrapNone :
5338                     aSet.Put( makeSdrTextAutoGrowWidthItem( true ) );
5339                     if (bFitText)
5340                     {
5341                         //can't do autowidth in flys #i107184#
5342                         pTextImpRec->bReplaceByFly = false;
5343                     }
5344                 break;
5345                 case mso_wrapByPoints :
5346                     aSet.Put( makeSdrTextContourFrameItem( true ) );
5347                 break;
5348                 default: break;
5349             }
5350 
5351             // set margins at the border of the textbox
5352             aSet.Put( makeSdrTextLeftDistItem( nTextLeft ) );
5353             aSet.Put( makeSdrTextRightDistItem( nTextRight ) );
5354             aSet.Put( makeSdrTextUpperDistItem( nTextTop ) );
5355             aSet.Put( makeSdrTextLowerDistItem( nTextBottom ) );
5356             pTextImpRec->nDxTextLeft    = nTextLeft;
5357             pTextImpRec->nDyTextTop     = nTextTop;
5358             pTextImpRec->nDxTextRight   = nTextRight;
5359             pTextImpRec->nDyTextBottom  = nTextBottom;
5360 
5361             // read text anchor
5362             if ( IsProperty( DFF_Prop_anchorText ) )
5363             {
5364                 auto eTextAnchor = GetPropertyValue(DFF_Prop_anchorText, 0);
5365 
5366                 SdrTextVertAdjust eTVA = SDRTEXTVERTADJUST_CENTER;
5367                 bool bTVASet(false);
5368                 bool bTHASet(false);
5369 
5370                 switch( eTextAnchor )
5371                 {
5372                     case mso_anchorTop:
5373                     {
5374                         eTVA = SDRTEXTVERTADJUST_TOP;
5375                         bTVASet = true;
5376                     }
5377                     break;
5378                     case mso_anchorTopCentered:
5379                     {
5380                         eTVA = SDRTEXTVERTADJUST_TOP;
5381                         bTVASet = true;
5382                         bTHASet = true;
5383                     }
5384                     break;
5385 
5386                     case mso_anchorMiddle:
5387                         bTVASet = true;
5388                     break;
5389                     case mso_anchorMiddleCentered:
5390                     {
5391                         bTVASet = true;
5392                         bTHASet = true;
5393                     }
5394                     break;
5395                     case mso_anchorBottom:
5396                     {
5397                         eTVA = SDRTEXTVERTADJUST_BOTTOM;
5398                         bTVASet = true;
5399                     }
5400                     break;
5401                     case mso_anchorBottomCentered:
5402                     {
5403                         eTVA = SDRTEXTVERTADJUST_BOTTOM;
5404                         bTVASet = true;
5405                         bTHASet = true;
5406                     }
5407                     break;
5408                     default : break;
5409                 }
5410                 // insert
5411                 if ( bTVASet )
5412                     aSet.Put( SdrTextVertAdjustItem( eTVA ) );
5413                 if ( bTHASet )
5414                     aSet.Put( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_CENTER ) );
5415             }
5416 
5417             pTextObj->SetMergedItemSet(aSet);
5418 
5419             if (bVerticalText)
5420                 pTextObj->SetVerticalWriting(true);
5421 
5422             if (nTextRotationAngle)
5423             {
5424                 tools::Long nMinWH = rTextRect.GetWidth() < rTextRect.GetHeight() ?
5425                     rTextRect.GetWidth() : rTextRect.GetHeight();
5426                 nMinWH /= 2;
5427                 Point aPivot(rTextRect.TopLeft());
5428                 aPivot.AdjustX(nMinWH );
5429                 aPivot.AdjustY(nMinWH );
5430                 pTextObj->SdrAttrObj::NbcRotate(aPivot, nTextRotationAngle);
5431             }
5432 
5433             // rotate text with shape?
5434             if ( mnFix16Angle )
5435             {
5436                 double a = mnFix16Angle.get() * F_PI18000;
5437                 pTextObj->NbcRotate( rObjData.aBoundRect.Center(), mnFix16Angle,
5438                     sin( a ), cos( a ) );
5439             }
5440 
5441             if( !pObj )
5442             {
5443                 pObj = pTextObj;
5444             }
5445             else
5446             {
5447                 if( pTextObj != pObj )
5448                 {
5449                     SdrObject* pGroup = new SdrObjGroup(*pSdrModel);
5450                     pGroup->GetSubList()->NbcInsertObject( pObj );
5451                     pGroup->GetSubList()->NbcInsertObject( pTextObj );
5452                     if (pOrgObj == pObj)
5453                         pOrgObj = pGroup;
5454                     else
5455                         pOrgObj = pObj;
5456                     pObj = pGroup;
5457                 }
5458             }
5459         }
5460         else if( !pObj )
5461         {
5462             // simple rectangular objects are ignored by ImportObj()  :-(
5463             // this is OK for Draw but not for Calc and Writer
5464             // cause here these objects have a default border
5465             pObj = new SdrRectObj(
5466                 *pSdrModel,
5467                 rTextRect);
5468 
5469             pOrgObj = pObj;
5470             SfxItemSet aSet( pSdrModel->GetItemPool() );
5471             ApplyAttributes( rSt, aSet, rObjData );
5472 
5473             const SfxPoolItem* pPoolItem=nullptr;
5474             SfxItemState eState = aSet.GetItemState( XATTR_FILLCOLOR,
5475                                                      false, &pPoolItem );
5476             if( SfxItemState::DEFAULT == eState )
5477                 aSet.Put( XFillColorItem( OUString(), mnDefaultColor ) );
5478             pObj->SetMergedItemSet(aSet);
5479         }
5480 
5481         //Means that fBehindDocument is set
5482         if (GetPropertyValue(DFF_Prop_fPrint, 0) & 0x20)
5483             pImpRec->bDrawHell = true;
5484         else
5485             pImpRec->bDrawHell = false;
5486         if (GetPropertyValue(DFF_Prop_fPrint, 0) & 0x02)
5487             pImpRec->bHidden = true;
5488         pTextImpRec->bDrawHell  = pImpRec->bDrawHell;
5489         pTextImpRec->bHidden = pImpRec->bHidden;
5490         pImpRec->nNextShapeId   = GetPropertyValue( DFF_Prop_hspNext, 0 );
5491         pTextImpRec->nNextShapeId=pImpRec->nNextShapeId;
5492 
5493         if ( nTextId )
5494         {
5495             pTextImpRec->aTextId.nTxBxS = static_cast<sal_uInt16>( nTextId >> 16 );
5496             pTextImpRec->aTextId.nSequence = static_cast<sal_uInt16>(nTextId);
5497         }
5498 
5499         pTextImpRec->nDxWrapDistLeft = GetPropertyValue(
5500                                     DFF_Prop_dxWrapDistLeft, 114935L ) / 635L;
5501         pTextImpRec->nDyWrapDistTop = GetPropertyValue(
5502                                     DFF_Prop_dyWrapDistTop, 0 ) / 635L;
5503         pTextImpRec->nDxWrapDistRight = GetPropertyValue(
5504                                     DFF_Prop_dxWrapDistRight, 114935L ) / 635L;
5505         pTextImpRec->nDyWrapDistBottom = GetPropertyValue(
5506                                     DFF_Prop_dyWrapDistBottom, 0 ) / 635L;
5507         // 16.16 fraction times total image width or height, as appropriate.
5508 
5509         if (SeekToContent(DFF_Prop_pWrapPolygonVertices, rSt))
5510         {
5511             pTextImpRec->pWrapPolygon.reset();
5512             sal_uInt16 nNumElemVert(0), nNumElemMemVert(0), nElemSizeVert(8);
5513             rSt.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert );
5514             // If this value is 0xFFF0 then this record is an array of truncated 8 byte elements. Only the 4
5515             // low-order bytes are recorded
5516             if (nElemSizeVert == 0xFFF0)
5517                 nElemSizeVert = 4;
5518 
5519             // sanity check that the stream is long enough to fulfill nNumElemVert * nElemSizeVert;
5520             bool bOk = nElemSizeVert && (rSt.remainingSize() / nElemSizeVert >= nNumElemVert);
5521             if (bOk)
5522             {
5523                 pTextImpRec->pWrapPolygon.reset(new tools::Polygon(nNumElemVert));
5524                 for (sal_uInt16 i = 0; i < nNumElemVert; ++i)
5525                 {
5526                     sal_Int32 nX(0), nY(0);
5527                     if (nElemSizeVert == 8)
5528                         rSt.ReadInt32( nX ).ReadInt32( nY );
5529                     else
5530                     {
5531                         sal_Int16 nSmallX(0), nSmallY(0);
5532                         rSt.ReadInt16( nSmallX ).ReadInt16( nSmallY );
5533                         nX = nSmallX;
5534                         nY = nSmallY;
5535                     }
5536                     (*(pTextImpRec->pWrapPolygon))[i].setX( nX );
5537                     (*(pTextImpRec->pWrapPolygon))[i].setY( nY );
5538                 }
5539             }
5540         }
5541 
5542         pImpRec->nCropFromTop = GetPropertyValue(
5543                                     DFF_Prop_cropFromTop, 0 );
5544         pImpRec->nCropFromBottom = GetPropertyValue(
5545                                     DFF_Prop_cropFromBottom, 0 );
5546         pImpRec->nCropFromLeft = GetPropertyValue(
5547                                     DFF_Prop_cropFromLeft, 0 );
5548         pImpRec->nCropFromRight = GetPropertyValue(
5549                                     DFF_Prop_cropFromRight, 0 );
5550 
5551         pImpRec->bVFlip = bool(rObjData.nSpFlags & ShapeFlag::FlipV);
5552         pImpRec->bHFlip = bool(rObjData.nSpFlags & ShapeFlag::FlipH);
5553 
5554         sal_uInt32 nLineFlags = GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 );
5555         pImpRec->eLineStyle = (nLineFlags & 8)
5556                             ? static_cast<MSO_LineStyle>(GetPropertyValue(
5557                                                 DFF_Prop_lineStyle,
5558                                                 mso_lineSimple ))
5559                             : MSO_LineStyle_NONE;
5560         pTextImpRec->eLineStyle = pImpRec->eLineStyle;
5561 
5562         pImpRec->eLineDashing = static_cast<MSO_LineDashing>(GetPropertyValue(
5563                 DFF_Prop_lineDashing, mso_lineSolid ));
5564         pTextImpRec->eLineDashing = pImpRec->eLineDashing;
5565 
5566         if( pImpRec->nShapeId )
5567         {
5568             // amend the import record list
5569             if( pOrgObj )
5570             {
5571                 pImpRec->pObj = pOrgObj;
5572                 rImportData.insert(std::unique_ptr<SvxMSDffImportRec>(pImpRec));
5573                 bDeleteImpRec = false;
5574                 if (pImpRec == pTextImpRec)
5575                     bDeleteTextImpRec = false;
5576             }
5577 
5578             if( pTextObj && (pOrgObj != pTextObj) )
5579             {
5580                 // Modify ShapeId (must be unique)
5581                 pImpRec->nShapeId |= 0x8000000;
5582                 pTextImpRec->pObj = pTextObj;
5583                 rImportData.insert(std::unique_ptr<SvxMSDffImportRec>(pTextImpRec));
5584                 bDeleteTextImpRec = false;
5585                 if (pTextImpRec == pImpRec)
5586                     bDeleteImpRec = false;
5587             }
5588 
5589             // entry in the z-order-list in order to complement the pointer to this object
5590             /*Only store objects which are not deep inside the tree*/
5591             if( ( rObjData.nCalledByGroup == 0 )
5592                 ||
5593                 ( (rObjData.nSpFlags & ShapeFlag::Group)
5594                  && (rObjData.nCalledByGroup < 2) )
5595               )
5596                 StoreShapeOrder( pImpRec->nShapeId,
5597                                 ( static_cast<sal_uLong>(pImpRec->aTextId.nTxBxS) << 16 )
5598                                     + pImpRec->aTextId.nSequence, pObj );
5599         }
5600 
5601         if (bDeleteImpRec)
5602             delete pImpRec;
5603 
5604         if (bDeleteTextImpRec)
5605             delete pTextImpRec;
5606     }
5607 
5608     return pObj;
5609 };
5610 
5611 SdrObject* SvxMSDffManager::FinalizeObj(DffObjData& /* rObjData */, SdrObject* pObj)
5612 {
5613     return pObj;
5614 }
5615 
5616 
5617 void SvxMSDffManager::StoreShapeOrder(sal_uLong         nId,
5618                                       sal_uLong         nTxBx,
5619                                       SdrObject*    pObject,
5620                                       SwFlyFrameFormat*  pFly) const
5621 {
5622     for (const auto& pOrder : m_aShapeOrders)
5623     {
5624         if (pOrder->nShapeId == nId)
5625         {
5626             pOrder->nTxBxComp = nTxBx;
5627             pOrder->pObj = pObject;
5628             pOrder->pFly = pFly;
5629         }
5630     }
5631 }
5632 
5633 
5634 void SvxMSDffManager::ExchangeInShapeOrder( SdrObject const * pOldObject,
5635                                             sal_uLong    nTxBx,
5636                                             SdrObject*   pObject) const
5637 {
5638     for (const auto& pOrder : m_aShapeOrders)
5639     {
5640         if (pOrder->pObj == pOldObject)
5641         {
5642             pOrder->pFly = nullptr;
5643             pOrder->pObj = pObject;
5644             pOrder->nTxBxComp = nTxBx;
5645         }
5646     }
5647 }
5648 
5649 
5650 void SvxMSDffManager::RemoveFromShapeOrder( SdrObject const * pObject ) const
5651 {
5652     for (const auto& pOrder : m_aShapeOrders)
5653     {
5654         if (pOrder->pObj == pObject)
5655         {
5656             pOrder->pObj = nullptr;
5657             pOrder->pFly = nullptr;
5658             pOrder->nTxBxComp = 0;
5659         }
5660     }
5661 }
5662 
5663 
5664 //  exported class: Public Methods
5665 
5666 SvxMSDffManager::SvxMSDffManager(SvStream& rStCtrl_,
5667                                  const OUString& rBaseURL,
5668                                  sal_uInt32 nOffsDgg_,
5669                                  SvStream* pStData_,
5670                                  SdrModel* pSdrModel_,// see SetModel() below
5671                                  tools::Long      nApplicationScale,
5672                                  Color     mnDefaultColor_,
5673                                  SvStream* pStData2_,
5674                                  bool bSkipImages )
5675     :DffPropertyReader( *this ),
5676      m_pBLIPInfos( new SvxMSDffBLIPInfos ),
5677      m_xShapeInfosByTxBxComp( new SvxMSDffShapeInfos_ByTxBxComp ),
5678      nOffsDgg( nOffsDgg_ ),
5679      nBLIPCount(  USHRT_MAX ),              // initialize with error, since we first check if the
5680      nGroupShapeFlags(ShapeFlag::NONE),     // ensure initialization here, as some corrupted
5681                                             // files may yield to this being uninitialized
5682      maBaseURL( rBaseURL ),
5683      mnIdClusters(0),
5684      rStCtrl(  rStCtrl_  ),
5685      pStData(  pStData_  ),
5686      pStData2( pStData2_ ),
5687      nSvxMSDffSettings( 0 ),
5688      nSvxMSDffOLEConvFlags( 0 ),
5689      mnDefaultColor( mnDefaultColor_),
5690      mbSkipImages (bSkipImages)
5691 {
5692     SetModel( pSdrModel_, nApplicationScale );
5693 
5694     // remember FilePos of the stream(s)
5695     sal_uInt64 nOldPosCtrl = rStCtrl.Tell();
5696     sal_uInt64 nOldPosData = pStData ? pStData->Tell() : nOldPosCtrl;
5697 
5698     // if no data stream is given we assume that the BLIPs
5699     // are in the control stream
5700     if( !pStData )
5701         pStData = &rStCtrl;
5702 
5703     SetDefaultPropSet( rStCtrl, nOffsDgg );
5704 
5705     // read control stream, if successful set nBLIPCount
5706     GetCtrlData( nOffsDgg );
5707 
5708     // check Text-Box-Story-Chain-Infos
5709     CheckTxBxStoryChain();
5710 
5711     // restore old FilePos of the stream(s)
5712     rStCtrl.Seek( nOldPosCtrl );
5713     if( &rStCtrl != pStData )
5714         pStData->Seek( nOldPosData );
5715 }
5716 
5717 SvxMSDffManager::SvxMSDffManager( SvStream& rStCtrl_, const OUString& rBaseURL )
5718     :DffPropertyReader( *this ),
5719      m_pBLIPInfos( new SvxMSDffBLIPInfos ),
5720      m_xShapeInfosByTxBxComp( new SvxMSDffShapeInfos_ByTxBxComp ),
5721      nOffsDgg( 0 ),
5722      nBLIPCount(  USHRT_MAX ),              // initialize with error, since we first have to check
5723      nGroupShapeFlags(ShapeFlag::NONE),
5724      maBaseURL( rBaseURL ),
5725      mnIdClusters(0),
5726      rStCtrl(  rStCtrl_  ),
5727      pStData( nullptr ),
5728      pStData2( nullptr ),
5729      nSvxMSDffSettings( 0 ),
5730      nSvxMSDffOLEConvFlags( 0 ),
5731      mnDefaultColor( COL_DEFAULT ),
5732      mbSkipImages(false)
5733 {
5734     SetModel( nullptr, 0 );
5735 }
5736 
5737 SvxMSDffManager::~SvxMSDffManager()
5738 {
5739 }
5740 
5741 void SvxMSDffManager::InitSvxMSDffManager( sal_uInt32 nOffsDgg_, SvStream* pStData_, sal_uInt32 nOleConvFlags )
5742 {
5743     nOffsDgg = nOffsDgg_;
5744     pStData = pStData_;
5745     nSvxMSDffOLEConvFlags = nOleConvFlags;
5746 
5747     // remember FilePos of the stream(s)
5748     sal_uInt64 nOldPosCtrl = rStCtrl.Tell();
5749 
5750     SetDefaultPropSet( rStCtrl, nOffsDgg );
5751 
5752     // insert fidcl cluster table
5753     GetFidclData( nOffsDgg );
5754 
5755     // read control stream, if successful, set nBLIPCount
5756     GetCtrlData( nOffsDgg );
5757 
5758     // check Text-Box-Story-Chain-Infos
5759     CheckTxBxStoryChain();
5760 
5761     // restore old FilePos of the stream(s)
5762     rStCtrl.Seek( nOldPosCtrl );
5763 }
5764 
5765 void SvxMSDffManager::SetDgContainer( SvStream& rSt )
5766 {
5767     sal_uInt64 nFilePos = rSt.Tell();
5768     DffRecordHeader aDgContHd;
5769     bool bOk = ReadDffRecordHeader(rSt, aDgContHd);
5770     // insert this container only if there is also a DggAtom
5771     if (bOk && SeekToRec(rSt, DFF_msofbtDg, aDgContHd.GetRecEndFilePos()))
5772     {
5773         DffRecordHeader aRecHd;
5774         if (ReadDffRecordHeader(rSt, aRecHd))
5775         {
5776             sal_uInt32 nDrawingId = aRecHd.nRecInstance;
5777             maDgOffsetTable[nDrawingId] = nFilePos;
5778         }
5779     }
5780     rSt.Seek(nFilePos);
5781 }
5782 
5783 void SvxMSDffManager::GetFidclData( sal_uInt32 nOffsDggL )
5784 {
5785     if (!nOffsDggL)
5786         return;
5787 
5788     sal_uInt64 nOldPos = rStCtrl.Tell();
5789 
5790     if (nOffsDggL == rStCtrl.Seek(nOffsDggL))
5791     {
5792         DffRecordHeader aRecHd;
5793         bool bOk = ReadDffRecordHeader(rStCtrl, aRecHd);
5794 
5795         DffRecordHeader aDggAtomHd;
5796         if (bOk && SeekToRec(rStCtrl, DFF_msofbtDgg, aRecHd.GetRecEndFilePos(), &aDggAtomHd))
5797         {
5798             aDggAtomHd.SeekToContent( rStCtrl );
5799             sal_uInt32 nCurMaxShapeId;
5800             sal_uInt32 nDummy;
5801             rStCtrl.ReadUInt32( nCurMaxShapeId )
5802                    .ReadUInt32( mnIdClusters )
5803                    .ReadUInt32( nDummy )
5804                    .ReadUInt32( nDummy ); // nDrawingsSaved
5805 
5806             if ( mnIdClusters-- > 2 )
5807             {
5808                 const std::size_t nFIDCLsize = sizeof(sal_uInt32) * 2;
5809                 if ( aDggAtomHd.nRecLen == ( mnIdClusters * nFIDCLsize + 16 ) )
5810                 {
5811                     sal_uInt64 nMaxEntriesPossible = rStCtrl.remainingSize() / nFIDCLsize;
5812                     SAL_WARN_IF(nMaxEntriesPossible < mnIdClusters,
5813                         "filter.ms", "FIDCL list longer than remaining bytes, ppt or parser is wrong");
5814                     mnIdClusters = std::min(nMaxEntriesPossible, static_cast<sal_uInt64>(mnIdClusters));
5815 
5816                     maFidcls.resize(mnIdClusters);
5817                     for (sal_uInt32 i = 0; i < mnIdClusters; ++i)
5818                     {
5819                         sal_uInt32  cspidCur;   ///< number of SPIDs used so far
5820                         rStCtrl.ReadUInt32( maFidcls[ i ].dgid )
5821                                .ReadUInt32( cspidCur );
5822                     }
5823                 }
5824             }
5825         }
5826     }
5827     rStCtrl.Seek( nOldPos );
5828 }
5829 
5830 void SvxMSDffManager::CheckTxBxStoryChain()
5831 {
5832     m_xShapeInfosById.reset(new SvxMSDffShapeInfos_ById);
5833     // mangle old Info array, sorted by nTxBxComp
5834     sal_uInt32 nChain = std::numeric_limits<sal_uInt32>::max();
5835     bool bSetReplaceFALSE = false;
5836     for (SvxMSDffShapeInfos_ByTxBxComp::iterator iter =
5837                 m_xShapeInfosByTxBxComp->begin(),
5838             mark = m_xShapeInfosByTxBxComp->begin();
5839          iter != m_xShapeInfosByTxBxComp->end(); ++iter)
5840     {
5841         std::shared_ptr<SvxMSDffShapeInfo> const pObj = *iter;
5842         if( pObj->nTxBxComp )
5843         {
5844             // group change?
5845             // the text id also contains an internal drawing container id
5846             // to distinguish between text id of drawing objects in different
5847             // drawing containers.
5848             if( nChain != pObj->nTxBxComp )
5849             {
5850                 // reset mark and helper flag
5851                 mark = iter;
5852                 nChain = pObj->nTxBxComp;
5853                 bSetReplaceFALSE = !pObj->bReplaceByFly;
5854             }
5855             else if( !pObj->bReplaceByFly )
5856             {
5857                 // object that must NOT be replaced by frame?
5858                 bSetReplaceFALSE = true;
5859                 // maybe reset flags in start of group
5860                 for (SvxMSDffShapeInfos_ByTxBxComp::iterator itemp = mark;
5861                         itemp != iter; ++itemp)
5862                 {
5863                     (*itemp)->bReplaceByFly = false;
5864                 }
5865             }
5866 
5867             if( bSetReplaceFALSE )
5868             {
5869                 pObj->bReplaceByFly = false;
5870             }
5871         }
5872         // copy all Shape Info objects to m_xShapeInfosById, sorted by nShapeId
5873         pObj->nTxBxComp = pObj->nTxBxComp & 0xFFFF0000;
5874         m_xShapeInfosById->insert( pObj );
5875     }
5876     // free original array but don't free its elements
5877     m_xShapeInfosByTxBxComp.reset();
5878 }
5879 
5880 
5881 /*****************************************************************************
5882 
5883     Reading the Shape-Infos in the Ctor:
5884     ---------------------------------
5885     remembering the Shape-Ids and the associated Blip-Numbers and TextBox-Infos
5886                     =========                    ============     =============
5887     and remembering the File-Offsets for each Blip
5888                        ============
5889 ******************************************************************************/
5890 void SvxMSDffManager::GetCtrlData(sal_uInt32 nOffsDggL)
5891 {
5892     // position control stream
5893     if (!checkSeek(rStCtrl, nOffsDggL))
5894         return;
5895 
5896     sal_uInt8   nVer;
5897     sal_uInt16 nInst;
5898     sal_uInt16 nFbt;
5899     sal_uInt32  nLength;
5900     if( !ReadCommonRecordHeader( rStCtrl, nVer, nInst, nFbt, nLength ) ) return;
5901 
5902     sal_uInt64 nPos = nOffsDggL + DFF_COMMON_RECORD_HEADER_SIZE;
5903 
5904     // case A: first Drawing Group Container, then n times Drawing Container
5905     if( DFF_msofbtDggContainer != nFbt )
5906         return;
5907 
5908     bool bOk;
5909     GetDrawingGroupContainerData( rStCtrl, nLength );
5910 
5911     sal_uInt64 nMaxStrPos = rStCtrl.TellEnd();
5912 
5913     nPos += nLength;
5914     sal_uInt16 nDrawingContainerId = 1;
5915     do
5916     {
5917         if (!checkSeek(rStCtrl, nPos))
5918             break;
5919 
5920         bOk = ReadCommonRecordHeader( rStCtrl, nVer, nInst, nFbt, nLength ) && ( DFF_msofbtDgContainer == nFbt );
5921 
5922         if( !bOk )
5923         {
5924             nPos++;                // ????????? TODO: trying to get a one-hit wonder, this code should be rewritten...
5925             if (nPos != rStCtrl.Seek(nPos))
5926                 break;
5927             bOk = ReadCommonRecordHeader( rStCtrl, nVer, nInst, nFbt, nLength )
5928                     && ( DFF_msofbtDgContainer == nFbt );
5929         }
5930         if( bOk )
5931         {
5932             GetDrawingContainerData( rStCtrl, nLength, nDrawingContainerId );
5933         }
5934         nPos += DFF_COMMON_RECORD_HEADER_SIZE + nLength;
5935         ++nDrawingContainerId;
5936     }
5937     while( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( nPos < nMaxStrPos ) && bOk );
5938 }
5939 
5940 
5941 // from here on: Drawing Group Container  i.e. document-wide valid data
5942 
5943 void SvxMSDffManager::GetDrawingGroupContainerData( SvStream& rSt, sal_uInt32 nLenDgg )
5944 {
5945     sal_uInt8   nVer;
5946     sal_uInt16 nInst;
5947     sal_uInt16 nFbt;
5948     sal_uInt32 nLength;
5949 
5950     sal_uInt32 nLenBStoreCont = 0, nLenFBSE = 0;
5951     sal_uLong nRead = 0;
5952 
5953     // search for a  BStore Container
5954     bool bOk = true;
5955     do
5956     {
5957         if (!ReadCommonRecordHeader(rSt, nVer, nInst, nFbt, nLength))
5958             return;
5959         nRead += DFF_COMMON_RECORD_HEADER_SIZE + nLength;
5960         if (DFF_msofbtBstoreContainer == nFbt)
5961         {
5962             nLenBStoreCont = nLength;
5963             break;
5964         }
5965         bOk = checkSeek(rSt, rSt.Tell() + nLength);
5966     }
5967     while (bOk && nRead < nLenDgg);
5968 
5969     if (!bOk || !nLenBStoreCont)
5970         return;
5971 
5972     // Read all atoms of the containers from the BStore container and store all
5973     // relevant data of all contained FBSEs in out pointer array.
5974     // We also count all found FBSEs in member nBLIPCount.
5975 
5976     const sal_uLong nSkipBLIPLen = 20;  // skip to get to the nBLIPLen
5977     const sal_uLong nSkipBLIPPos =  4;  // thereafter skip up to nBLIPPos
5978 
5979     sal_uInt32 nBLIPLen = 0, nBLIPPos = 0;
5980 
5981     nRead = 0;
5982     do
5983     {
5984         if(!ReadCommonRecordHeader( rSt, nVer, nInst, nFbt, nLength)) return;
5985         nRead += DFF_COMMON_RECORD_HEADER_SIZE + nLength;
5986         if( DFF_msofbtBSE == nFbt && /* magic value from spec */ 0x2 == nVer )
5987         {
5988             nLenFBSE = nLength;
5989             // is FBSE big enough for our data
5990             bOk = ( nSkipBLIPLen + 4 + nSkipBLIPPos + 4 <= nLenFBSE );
5991 
5992             if (bOk)
5993             {
5994                 rSt.SeekRel( nSkipBLIPLen );
5995                 rSt.ReadUInt32( nBLIPLen );
5996                 rSt.SeekRel( nSkipBLIPPos );
5997                 rSt.ReadUInt32( nBLIPPos );
5998                 bOk = rSt.GetError() == ERRCODE_NONE;
5999 
6000                 nLength -= nSkipBLIPLen+ 4 + nSkipBLIPPos + 4;
6001             }
6002 
6003             if (bOk)
6004             {
6005                 // specialty:
6006                 // If nBLIPLen is less than nLenFBSE AND nBLIPPos is NULL,
6007                 // then we assume, that the image is in FBSE!
6008                 if( (!nBLIPPos) && (nBLIPLen < nLenFBSE) )
6009                     nBLIPPos = rSt.Tell() + 4;
6010 
6011                 if( USHRT_MAX == nBLIPCount )
6012                     nBLIPCount = 1;
6013                 else
6014                     nBLIPCount++;
6015 
6016                 // now save the info for later access
6017                 m_pBLIPInfos->push_back(SvxMSDffBLIPInfo(nBLIPPos));
6018             }
6019             if (!checkSeek(rSt, rSt.Tell() + nLength))
6020                 return; // invalid offset
6021         }
6022         else return; // invalid input
6023     }
6024     while( nRead < nLenBStoreCont );
6025 }
6026 
6027 
6028 // from now on: Drawing Container  which means Pages (Sheet, Slide) - wide valid data
6029 //                      =================               ======
6030 
6031 void SvxMSDffManager::GetDrawingContainerData( SvStream& rSt, sal_uInt32 nLenDg,
6032                                                sal_uInt16 nDrawingContainerId )
6033 {
6034     sal_uInt8 nVer;sal_uInt16 nInst;sal_uInt16 nFbt;sal_uInt32 nLength;
6035 
6036     sal_uLong nReadDg = 0;
6037 
6038     // We are now in a drawing container (one per each page) and
6039     // we now have to iterate through all contained shape group containers
6040     do
6041     {
6042         if (!ReadCommonRecordHeader(rSt, nVer, nInst, nFbt, nLength))
6043             return;
6044         nReadDg += DFF_COMMON_RECORD_HEADER_SIZE;
6045         // Patriarch found (the upmost shape group container) ?
6046         if (DFF_msofbtSpgrContainer == nFbt)
6047         {
6048             if (!GetShapeGroupContainerData(rSt, nLength, true, nDrawingContainerId))
6049                 return;
6050         }
6051         // empty Shape Container ? (outside of shape group container)
6052         else if (DFF_msofbtSpContainer == nFbt)
6053         {
6054             if (!GetShapeContainerData(
6055                     rSt, nLength, std::numeric_limits<sal_uInt64>::max(), nDrawingContainerId))
6056                 return;
6057         }
6058         else
6059         {
6060             if (!checkSeek(rSt, rSt.Tell() + nLength))
6061                 return;
6062         }
6063         nReadDg += nLength;
6064     }
6065     while( nReadDg < nLenDg );
6066 }
6067 
6068 bool SvxMSDffManager::GetShapeGroupContainerData( SvStream& rSt,
6069                                                   sal_uInt32 nLenShapeGroupCont,
6070                                                   bool bPatriarch,
6071                                                   sal_uInt16 nDrawingContainerId )
6072 {
6073     sal_uInt8 nVer;sal_uInt16 nInst;sal_uInt16 nFbt;sal_uInt32 nLength;
6074     sal_uInt64 nStartShapeGroupCont = rSt.Tell();
6075     // We are now in a shape group container (conditionally multiple per page)
6076     // and we now have to iterate through all contained shape containers
6077     bool  bFirst = !bPatriarch;
6078     sal_uLong nReadSpGrCont = 0;
6079     do
6080     {
6081         if( !ReadCommonRecordHeader( rSt, nVer, nInst, nFbt, nLength ) )
6082             return false;
6083         nReadSpGrCont += DFF_COMMON_RECORD_HEADER_SIZE;
6084         // Shape Container?
6085         if( DFF_msofbtSpContainer == nFbt )
6086         {
6087             sal_uInt64 nGroupOffs = bFirst ? nStartShapeGroupCont - DFF_COMMON_RECORD_HEADER_SIZE : std::numeric_limits<sal_uInt64>::max();
6088             if ( !GetShapeContainerData( rSt, nLength, nGroupOffs, nDrawingContainerId ) )
6089                 return false;
6090             bFirst = false;
6091         }
6092         // nested shape group container ?
6093         else if( DFF_msofbtSpgrContainer == nFbt )
6094         {
6095             if ( !GetShapeGroupContainerData( rSt, nLength, false, nDrawingContainerId ) )
6096                 return false;
6097         }
6098         else
6099         {
6100             if (!checkSeek(rSt, rSt.Tell() + nLength))
6101                 return false;
6102         }
6103         nReadSpGrCont += nLength;
6104     }
6105     while( nReadSpGrCont < nLenShapeGroupCont );
6106     // position the stream correctly
6107     rSt.Seek( nStartShapeGroupCont + nLenShapeGroupCont );
6108     return true;
6109 }
6110 
6111 bool SvxMSDffManager::GetShapeContainerData( SvStream& rSt,
6112                                              sal_uInt32 nLenShapeCont,
6113                                              sal_uInt64 nPosGroup,
6114                                              sal_uInt16 nDrawingContainerId )
6115 {
6116     sal_uInt8 nVer;sal_uInt16 nInst;sal_uInt16 nFbt;sal_uInt32 nLength;
6117     sal_uInt64 nStartShapeCont = rSt.Tell();
6118 
6119     // We are in a shape container (possibly more than one per shape group) and we now
6120     // have to fetch the shape id and file position (to be able to access them again later)
6121     // and the first BStore reference (if present).
6122     sal_uInt32 nLenShapePropTbl = 0;
6123     sal_uLong nReadSpCont = 0;
6124 
6125     // Store file offset of the shape containers or respectively the group(!).
6126     sal_uInt64 nStartOffs = (std::numeric_limits<sal_uInt64>::max() > nPosGroup) ?
6127                             nPosGroup : nStartShapeCont - DFF_COMMON_RECORD_HEADER_SIZE;
6128     SvxMSDffShapeInfo aInfo( nStartOffs );
6129 
6130     // Can the shape be replaced with a frame?
6131     // (provided that it is a TextBox and the text is not rotated)
6132     bool bCanBeReplaced = nPosGroup >= std::numeric_limits<sal_uInt64>::max();
6133 
6134     // we don't know yet whether it's a TextBox
6135     MSO_SPT         eShapeType      = mso_sptNil;
6136 
6137     // analyze Shape
6138 
6139     do
6140     {
6141         if(!ReadCommonRecordHeader( rSt, nVer, nInst, nFbt, nLength)) return false;
6142         nReadSpCont += DFF_COMMON_RECORD_HEADER_SIZE;
6143         // FSP ?
6144         if( ( DFF_msofbtSp == nFbt ) && ( 4 <= nLength ) )
6145         {
6146             // we've found the FSP: note Shape Type and Id!
6147             eShapeType = static_cast<MSO_SPT>(nInst);
6148             rSt.ReadUInt32( aInfo.nShapeId );
6149             rSt.SeekRel( nLength - 4 );
6150             nReadSpCont += nLength;
6151         }
6152         else if( DFF_msofbtOPT == nFbt ) // Shape Property Table ?
6153         {
6154             // We've found the Property Table:
6155             // search for the Blip Property!
6156             sal_uLong  nPropRead = 0;
6157             nLenShapePropTbl = nLength;
6158             auto nStartShapePropTbl = rSt.Tell();
6159             do
6160             {
6161                 sal_uInt16 nPropId(0);
6162                 sal_uInt32 nPropVal(0);
6163 
6164                 rSt.ReadUInt16( nPropId )
6165                    .ReadUInt32( nPropVal );
6166                 nPropRead += 6;
6167 
6168                 switch( nPropId )
6169                 {
6170                     case DFF_Prop_txflTextFlow :
6171                         //Writer can now handle vertical textflows in its
6172                         //native frames, to only need to do this for the
6173                         //other two formats
6174 
6175                         //Writer will handle all textflow except BtoT
6176                         if (GetSvxMSDffSettings() &
6177                             (SVXMSDFF_SETTINGS_IMPORT_PPT |
6178                              SVXMSDFF_SETTINGS_IMPORT_EXCEL))
6179                         {
6180                             if( 0 != nPropVal )
6181                                 bCanBeReplaced = false;
6182                         }
6183                         else if (
6184                             (nPropVal != mso_txflHorzN) &&
6185                             (nPropVal != mso_txflTtoBA)
6186                                 )
6187                         {
6188                             bCanBeReplaced = false;
6189                         }
6190                     break;
6191                     case DFF_Prop_cdirFont :
6192                         //Writer can now handle right to left and left
6193                         //to right in its native frames, so only do
6194                         //this for the other two formats.
6195                         if (GetSvxMSDffSettings() &
6196                             (SVXMSDFF_SETTINGS_IMPORT_PPT |
6197                              SVXMSDFF_SETTINGS_IMPORT_EXCEL))
6198                         {
6199                             if( 0 != nPropVal )
6200                                 bCanBeReplaced = false;
6201                         }
6202                     break;
6203                     case DFF_Prop_Rotation :
6204                         if( 0 != nPropVal )
6205                             bCanBeReplaced = false;
6206                     break;
6207 
6208                     case DFF_Prop_gtextFStrikethrough :
6209                         if( ( 0x20002000 & nPropVal )  == 0x20002000 )
6210                             bCanBeReplaced = false;
6211                     break;
6212 
6213                     case DFF_Prop_fc3DLightFace :
6214                         if( ( 0x00080008 & nPropVal ) == 0x00080008 )
6215                             bCanBeReplaced = false;
6216                     break;
6217 
6218                     case DFF_Prop_WrapText :
6219                         //TODO: eWrapMode = (MSO_WrapMode)nPropVal;
6220                     break;
6221 
6222                     default:
6223                     {
6224                         // is the Bit set and valid?
6225                         if( 0x4000 == ( nPropId & 0xC000 ) )
6226                         {
6227                             // Blip Property found: remember BStore Idx!
6228                             nPropRead = nLenShapePropTbl;
6229                         }
6230                         else if( 0x8000 & nPropId )
6231                         {
6232                             // complex Prop found:
6233                             // Length is always 6. The length of the appended extra data
6234                             // after the actual prop table is of different size.
6235                             nPropVal = 6;
6236                         }
6237                     }
6238                     break;
6239                 }
6240             }
6241             while (rSt.good() && nPropRead < nLenShapePropTbl);
6242             rSt.Seek( nStartShapePropTbl + nLenShapePropTbl );
6243             nReadSpCont += nLenShapePropTbl;
6244         }
6245         else if( ( DFF_msofbtClientTextbox == nFbt ) && ( 4 == nLength ) )  // Text-Box-Story-Entry found
6246         {
6247             rSt.ReadUInt32( aInfo.nTxBxComp );
6248             // Add internal drawing container id to text id.
6249             // Note: The text id uses the first two bytes, while the internal
6250             // drawing container id used the second two bytes.
6251             aInfo.nTxBxComp = ( aInfo.nTxBxComp & 0xFFFF0000 ) +
6252                               nDrawingContainerId;
6253             DBG_ASSERT( (aInfo.nTxBxComp & 0x0000FFFF) == nDrawingContainerId,
6254                         "<SvxMSDffManager::GetShapeContainerData(..)> - internal drawing container Id could not be correctly merged into DFF_msofbtClientTextbox value." );
6255         }
6256         else
6257         {
6258             if (!checkSeek(rSt, rSt.Tell() + nLength))
6259             {
6260                 SAL_WARN("filter.ms", "remaining record longer than available data, ppt or parser is wrong");
6261                 break;
6262             }
6263             nReadSpCont += nLength;
6264         }
6265     }
6266     while( nReadSpCont < nLenShapeCont );
6267 
6268 
6269     // Now possibly store the information for subsequent accesses to the shape
6270 
6271     if( aInfo.nShapeId )
6272     {
6273         // Possibly allow replacement of textboxes with frames
6274         if(     bCanBeReplaced
6275              && aInfo.nTxBxComp
6276              && (
6277                     ( eShapeType == mso_sptTextSimple )
6278                  || ( eShapeType == mso_sptTextBox    )
6279                  || ( eShapeType == mso_sptRectangle  )
6280                  || ( eShapeType == mso_sptRoundRectangle )
6281                 ) )
6282         {
6283             aInfo.bReplaceByFly = true;
6284         }
6285         m_xShapeInfosByTxBxComp->insert(std::make_shared<SvxMSDffShapeInfo>(
6286                     aInfo));
6287         m_aShapeOrders.push_back(std::make_unique<SvxMSDffShapeOrder>(
6288                     aInfo.nShapeId ));
6289     }
6290 
6291     // and position the Stream correctly again
6292     rSt.Seek( nStartShapeCont + nLenShapeCont );
6293     return true;
6294 }
6295 
6296 
6297 /*****************************************************************************
6298 
6299     Access to a shape at runtime (via the Shape-Id)
6300     ----------------------------
6301 ******************************************************************************/
6302 bool SvxMSDffManager::GetShape(sal_uLong nId, SdrObject*&         rpShape,
6303                                           SvxMSDffImportData& rData)
6304 {
6305     auto const pTmpRec = std::make_shared<SvxMSDffShapeInfo>(0, nId);
6306 
6307     SvxMSDffShapeInfos_ById::const_iterator const it =
6308         m_xShapeInfosById->find(pTmpRec);
6309     if (it != m_xShapeInfosById->end())
6310     {
6311         // Possibly delete old error flag.
6312         if( rStCtrl.GetError() )
6313             rStCtrl.ResetError();
6314         // store FilePos of the stream(s)
6315         sal_uInt64 nOldPosCtrl = rStCtrl.Tell();
6316         sal_uInt64 nOldPosData = pStData ? pStData->Tell() : nOldPosCtrl;
6317         // jump to the shape in the control stream
6318         sal_uInt64 const nFilePos((*it)->nFilePos);
6319         bool bSeeked = (nFilePos == rStCtrl.Seek(nFilePos));
6320 
6321         // if it failed, reset error statusF
6322         if (!bSeeked || rStCtrl.GetError())
6323             rStCtrl.ResetError();
6324         else
6325             rpShape = ImportObj( rStCtrl, rData, rData.aParentRect, rData.aParentRect, /*nCalledByGroup*/0, /*pShapeId*/nullptr );
6326 
6327         // restore old FilePos of the stream(s)
6328         rStCtrl.Seek( nOldPosCtrl );
6329         if( &rStCtrl != pStData && pStData )
6330             pStData->Seek( nOldPosData );
6331         return ( nullptr != rpShape );
6332     }
6333     return false;
6334 }
6335 
6336 
6337 /** Access to a BLIP at runtime (if the Blip-Number is already known)
6338  */
6339 bool SvxMSDffManager::GetBLIP( sal_uLong nIdx_, Graphic& rGraphic, tools::Rectangle* pVisArea )
6340 {
6341     if (!pStData)
6342         return false;
6343 
6344     bool bOk = false;       // initialize result variable
6345 
6346     // check if a graphic for this blipId is already imported
6347     if (nIdx_)
6348     {
6349         auto iter = aEscherBlipCache.find(nIdx_);
6350 
6351         if (iter != aEscherBlipCache.end())
6352         {
6353             /* if this entry is available */
6354             rGraphic = iter->second;
6355             if (rGraphic.GetType() != GraphicType::NONE)
6356                 bOk = true;
6357             else
6358                 aEscherBlipCache.erase(iter);
6359         }
6360     }
6361 
6362     if (!bOk)
6363     {
6364         sal_uInt16 nIdx = sal_uInt16( nIdx_ );
6365         if (!nIdx || (m_pBLIPInfos->size() < nIdx))
6366             return false;
6367 
6368         // possibly delete old error flag(s)
6369         if( rStCtrl.GetError() )
6370             rStCtrl.ResetError();
6371         if(    ( &rStCtrl != pStData )
6372             && pStData->GetError() )
6373             pStData->ResetError();
6374 
6375         // remember FilePos of the stream(s)
6376         sal_uInt64 nOldPosCtrl = rStCtrl.Tell();
6377         sal_uInt64 nOldPosData = pStData->Tell();
6378 
6379         // fetch matching info struct out of the pointer array
6380         SvxMSDffBLIPInfo& rInfo = (*m_pBLIPInfos)[ nIdx-1 ];
6381         // jump to the BLIP atom in the data stream
6382         bOk = checkSeek(*pStData, rInfo.nFilePos);
6383         // possibly reset error status
6384         if (!bOk || pStData->GetError())
6385             pStData->ResetError();
6386         else
6387             bOk = GetBLIPDirect( *pStData, rGraphic, pVisArea );
6388         if( pStData2 && !bOk )
6389         {
6390             // Error, but the is a second chance: There is a second
6391             //         data stream in which the graphic could be stored!
6392             if( pStData2->GetError() )
6393                 pStData2->ResetError();
6394             sal_uInt64 nOldPosData2 = pStData2->Tell();
6395             // jump to the BLIP atom in the second data stream
6396             bOk = checkSeek(*pStData2, rInfo.nFilePos);
6397             // reset error status if necessary
6398             if (!bOk || pStData2->GetError())
6399                 pStData2->ResetError();
6400             else
6401                 bOk = GetBLIPDirect( *pStData2, rGraphic, pVisArea );
6402             // restore of FilePos of the second data stream
6403             pStData2->Seek( nOldPosData2 );
6404         }
6405         // restore old FilePos of the stream(s)
6406         rStCtrl.Seek( nOldPosCtrl );
6407         if( &rStCtrl != pStData )
6408           pStData->Seek( nOldPosData );
6409 
6410         if (bOk)
6411         {
6412             // create new BlipCacheEntry for this graphic
6413             aEscherBlipCache.insert(std::make_pair(nIdx_, rGraphic));
6414         }
6415     }
6416 
6417     return bOk;
6418 }
6419 
6420 /*      access to a BLIP at runtime (with correctly positioned stream)
6421     ---------------------------------
6422 ******************************************************************************/
6423 bool SvxMSDffManager::GetBLIPDirect( SvStream& rBLIPStream, Graphic& rData, tools::Rectangle* pVisArea )
6424 {
6425     sal_uInt64 nOldPos = rBLIPStream.Tell();
6426 
6427     ErrCode nRes = ERRCODE_GRFILTER_OPENERROR;  // initialize error variable
6428 
6429     // check whether it's really a BLIP
6430     sal_uInt32 nLength;
6431     sal_uInt16 nInst, nFbt( 0 );
6432     sal_uInt8   nVer;
6433     if( ReadCommonRecordHeader( rBLIPStream, nVer, nInst, nFbt, nLength) && ( 0xF018 <= nFbt ) && ( 0xF117 >= nFbt ) )
6434     {
6435         Size        aMtfSize100;
6436         bool        bMtfBLIP = false;
6437         bool        bZCodecCompression = false;
6438         // now position it exactly at the beginning of the embedded graphic
6439         sal_uLong nSkip = ( nInst & 0x0001 ) ? 32 : 16;
6440 
6441         switch( nInst & 0xFFFE )
6442         {
6443             case 0x216 :            // Metafile header then compressed WMF
6444             case 0x3D4 :            // Metafile header then compressed EMF
6445             case 0x542 :            // Metafile hd. then compressed PICT
6446             {
6447                 rBLIPStream.SeekRel( nSkip + 20 );
6448 
6449                 // read in size of metafile in EMUS
6450                 sal_Int32 width(0), height(0);
6451                 rBLIPStream.ReadInt32( width ).ReadInt32( height );
6452                 aMtfSize100.setWidth( width );
6453                 aMtfSize100.setHeight( height );
6454 
6455                 // scale to 1/100mm
6456                 aMtfSize100.setWidth( aMtfSize100.Width() / 360 );
6457                 aMtfSize100.setHeight( aMtfSize100.Height() / 360 );
6458 
6459                 if ( pVisArea )     // seem that we currently are skipping the visarea position
6460                     *pVisArea = tools::Rectangle( Point(), aMtfSize100 );
6461 
6462                 // skip rest of header
6463                 nSkip = 6;
6464                 bMtfBLIP = bZCodecCompression = true;
6465             }
6466             break;
6467             case 0x46A :            // One byte tag then JPEG (= JFIF) data
6468             case 0x6E0 :            // One byte tag then PNG data
6469             case 0x6E2 :            // One byte tag then JPEG in CMYK color space
6470             case 0x7A8 :
6471                 nSkip += 1;         // One byte tag then DIB data
6472             break;
6473         }
6474         rBLIPStream.SeekRel( nSkip );
6475 
6476         SvStream* pGrStream = &rBLIPStream;
6477         std::unique_ptr<SvMemoryStream> xOut;
6478         if( bZCodecCompression )
6479         {
6480             xOut.reset(new SvMemoryStream( 0x8000, 0x4000 ));
6481             ZCodec aZCodec( 0x8000, 0x8000 );
6482             aZCodec.BeginCompression();
6483             aZCodec.Decompress( rBLIPStream, *xOut );
6484             aZCodec.EndCompression();
6485             xOut->Seek( STREAM_SEEK_TO_BEGIN );
6486             xOut->SetResizeOffset( 0 ); // sj: #i102257# setting ResizeOffset of 0 prevents from seeking
6487                                         // behind the stream end (allocating too much memory)
6488             pGrStream = xOut.get();
6489         }
6490 
6491 #ifdef DEBUG_FILTER_MSDFFIMP
6492         // extract graphics from ole storage into "dbggfxNNN.*"
6493         static sal_Int32 nGrfCount;
6494 
6495         OUString aFileName = "dbggfx" + OUString::number( nGrfCount++ );
6496         switch( nInst &~ 1 )
6497         {
6498             case 0x216 : aFileName += ".wmf"; break;
6499             case 0x3d4 : aFileName += ".emf"; break;
6500             case 0x542 : aFileName += ".pct"; break;
6501             case 0x46a : aFileName += ".jpg"; break;
6502             case 0x6e0 : aFileName += ".png"; break;
6503             case 0x6e2 : aFileName += ".jpg"; break;
6504             case 0x7a8 : aFileName += ".bmp"; break;
6505         }
6506 
6507         OUString aURLStr;
6508         if( osl::FileBase::getFileURLFromSystemPath( Application::GetAppFileName(), aURLStr ) == osl::FileBase::E_None )
6509         {
6510             INetURLObject aURL( aURLStr );
6511 
6512             aURL.removeSegment();
6513             aURL.removeFinalSlash();
6514             aURL.Append( aFileName );
6515 
6516             aURLStr = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
6517 
6518             SAL_INFO("filter.ms", "dumping " << aURLStr);
6519 
6520             std::unique_ptr<SvStream> pDbgOut(::utl::UcbStreamHelper::CreateStream(aURLStr, StreamMode::TRUNC | StreamMode::WRITE));
6521 
6522             if( pDbgOut )
6523             {
6524                 if ( bZCodecCompression )
6525                 {
6526                     pDbgOut->WriteBytes(xOut->GetData(), xOut->TellEnd());
6527                     xOut->Seek(STREAM_SEEK_TO_BEGIN);
6528                 }
6529                 else
6530                 {
6531                     sal_Int32 nDbgLen = nLength - nSkip;
6532                     if ( nDbgLen )
6533                     {
6534                         std::vector<char> aData(nDbgLen);
6535                         pGrStream->ReadBytes(aData.data(), nDbgLen);
6536                         pDbgOut->WriteBytes(aData.data(), nDbgLen);
6537                         pGrStream->SeekRel(-nDbgLen);
6538                     }
6539                 }
6540             }
6541         }
6542 #endif
6543 
6544         if( ( nInst & 0xFFFE ) == 0x7A8 )
6545         {   // getting the DIBs immediately
6546             Bitmap aNew;
6547             if( ReadDIB(aNew, *pGrStream, false) )
6548             {
6549                 rData = Graphic(BitmapEx(aNew));
6550                 nRes = ERRCODE_NONE;
6551             }
6552         }
6553         else
6554         {   // and unleash our filter
6555             GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
6556             // ImportUnloadedGraphic() may simply read the entire rest of the stream,
6557             // which may be very large if the whole document is large. Limit the read
6558             // size to the size of this record.
6559             sal_uInt64 maxSize = pGrStream == &rBLIPStream ? nLength : 0;
6560             Graphic aGraphic;
6561 
6562             // Size available in metafile header.
6563             if (aMtfSize100.getWidth() && aMtfSize100.getHeight())
6564                 aGraphic = rGF.ImportUnloadedGraphic(*pGrStream, maxSize, &aMtfSize100);
6565             else
6566                 aGraphic = rGF.ImportUnloadedGraphic(*pGrStream, maxSize);
6567 
6568             if (!aGraphic.IsNone())
6569             {
6570                 rData = aGraphic;
6571                 nRes = ERRCODE_NONE;
6572             }
6573             else
6574                 nRes = rGF.ImportGraphic( rData, "", *pGrStream );
6575 
6576             // SJ: I40472, sometimes the aspect ratio (aMtfSize100) does not match and we get scaling problems,
6577             // then it is better to use the prefsize that is stored within the metafile. Bug #72846# for what the
6578             // scaling has been implemented does not happen anymore.
6579             //
6580             // For pict graphics we will furthermore scale the metafile, because font scaling leads to error if the
6581             // dxarray is empty (this has been solved in wmf/emf but not for pict)
6582             if( bMtfBLIP && ( ERRCODE_NONE == nRes ) && ( rData.GetType() == GraphicType::GdiMetafile ) && ( ( nInst & 0xFFFE ) == 0x542 ) )
6583             {
6584                 if ( ( aMtfSize100.Width() >= 1000 ) && ( aMtfSize100.Height() >= 1000 ) )
6585                 {   // #75956#, scaling does not work properly, if the graphic is less than 1cm
6586                     GDIMetaFile aMtf( rData.GetGDIMetaFile() );
6587                     const Size  aOldSize( aMtf.GetPrefSize() );
6588 
6589                     if( aOldSize.Width() && ( aOldSize.Width() != aMtfSize100.Width() ) &&
6590                         aOldSize.Height() && ( aOldSize.Height() != aMtfSize100.Height() ) )
6591                     {
6592                         aMtf.Scale( static_cast<double>(aMtfSize100.Width()) / aOldSize.Width(),
6593                                     static_cast<double>(aMtfSize100.Height()) / aOldSize.Height() );
6594                         aMtf.SetPrefSize( aMtfSize100 );
6595                         aMtf.SetPrefMapMode(MapMode(MapUnit::Map100thMM));
6596                         rData = aMtf;
6597                     }
6598                 }
6599             }
6600         }
6601         // reset error status if necessary
6602         if ( ERRCODE_IO_PENDING == pGrStream->GetError() )
6603           pGrStream->ResetError();
6604     }
6605     rBLIPStream.Seek( nOldPos );    // restore old FilePos of the stream
6606 
6607     return ( ERRCODE_NONE == nRes ); // return result
6608 }
6609 
6610 /* also static */
6611 bool SvxMSDffManager::ReadCommonRecordHeader(SvStream& rSt,
6612     sal_uInt8& rVer, sal_uInt16& rInst, sal_uInt16& rFbt, sal_uInt32& rLength)
6613 {
6614     sal_uInt16 nTmp(0);
6615     rSt.ReadUInt16( nTmp ).ReadUInt16( rFbt ).ReadUInt32( rLength );
6616     rVer = sal::static_int_cast< sal_uInt8 >(nTmp & 15);
6617     rInst = nTmp >> 4;
6618     if (!rSt.good())
6619         return false;
6620     if (rLength > nMaxLegalDffRecordLength)
6621         return false;
6622     return true;
6623 }
6624 
6625 void SvxMSDffManager::ProcessClientAnchor(SvStream& rStData, sal_uInt32 nDatLen,
6626                                           std::unique_ptr<char[]>& rpBuff, sal_uInt32& rBuffLen )
6627 {
6628     if( nDatLen )
6629     {
6630         rBuffLen = std::min(rStData.remainingSize(), static_cast<sal_uInt64>(nDatLen));
6631         rpBuff.reset( new char[rBuffLen] );
6632         rBuffLen = rStData.ReadBytes(rpBuff.get(), rBuffLen);
6633     }
6634 }
6635 
6636 void SvxMSDffManager::ProcessClientData(SvStream& rStData, sal_uInt32 nDatLen,
6637                                         std::unique_ptr<char[]>& rpBuff, sal_uInt32& rBuffLen )
6638 {
6639     if( nDatLen )
6640     {
6641         rBuffLen = std::min(rStData.remainingSize(), static_cast<sal_uInt64>(nDatLen));
6642         rpBuff.reset( new char[rBuffLen] );
6643         rBuffLen = rStData.ReadBytes(rpBuff.get(), rBuffLen);
6644     }
6645 }
6646 
6647 
6648 void SvxMSDffManager::ProcessClientAnchor2( SvStream& /* rSt */, DffRecordHeader& /* rHd */ , DffObjData& /* rObj */ )
6649 {
6650     // will be overridden by SJ in Draw
6651 }
6652 
6653 bool SvxMSDffManager::GetOLEStorageName( sal_uInt32, OUString&, tools::SvRef<SotStorage>&, uno::Reference < embed::XStorage >& ) const
6654 {
6655     return false;
6656 }
6657 
6658 bool SvxMSDffManager::ShapeHasText( sal_uLong /* nShapeId */, sal_uLong /* nFilePos */ ) const
6659 {
6660     return true;
6661 }
6662 
6663 // #i32596# - add new parameter <_nCalledByGroup>
6664 SdrObject* SvxMSDffManager::ImportOLE( sal_uInt32 nOLEId,
6665                                        const Graphic& rGrf,
6666                                        const tools::Rectangle& rBoundRect,
6667                                        const tools::Rectangle& rVisArea,
6668                                        const int /* _nCalledByGroup */ ) const
6669 {
6670     SdrObject* pRet = nullptr;
6671     OUString sStorageName;
6672     tools::SvRef<SotStorage> xSrcStg;
6673     ErrCode nError = ERRCODE_NONE;
6674     uno::Reference < embed::XStorage > xDstStg;
6675     if( GetOLEStorageName( nOLEId, sStorageName, xSrcStg, xDstStg ))
6676         pRet = CreateSdrOLEFromStorage(
6677             *GetModel(),
6678             sStorageName,
6679             xSrcStg,
6680             xDstStg,
6681             rGrf,
6682             rBoundRect,
6683             rVisArea,
6684             pStData,
6685             nError,
6686             nSvxMSDffOLEConvFlags,
6687             embed::Aspects::MSOLE_CONTENT,
6688             maBaseURL);
6689     return pRet;
6690 }
6691 
6692 bool SvxMSDffManager::MakeContentStream( SotStorage * pStor, const GDIMetaFile & rMtf )
6693 {
6694     tools::SvRef<SotStorageStream> xStm = pStor->OpenSotStream(SVEXT_PERSIST_STREAM);
6695     xStm->SetVersion( pStor->GetVersion() );
6696     xStm->SetBufferSize( 8192 );
6697 
6698     Impl_OlePres aEle;
6699     // Convert the size in 1/100 mm
6700     // If a not applicable MapUnit (device dependent) is used,
6701     // SV tries to guess a best match for the right value
6702     Size aSize = rMtf.GetPrefSize();
6703     const MapMode& aMMSrc = rMtf.GetPrefMapMode();
6704     MapMode aMMDst( MapUnit::Map100thMM );
6705     aSize = OutputDevice::LogicToLogic( aSize, aMMSrc, aMMDst );
6706     aEle.SetSize( aSize );
6707     aEle.SetAspect( ASPECT_CONTENT );
6708     aEle.SetAdviseFlags( 2 );
6709     aEle.SetMtf( rMtf );
6710     aEle.Write( *xStm );
6711 
6712     xStm->SetBufferSize( 0 );
6713     return xStm->GetError() == ERRCODE_NONE;
6714 }
6715 
6716 namespace {
6717 
6718 struct ClsIDs {
6719     sal_uInt32  nId;
6720     const char* pSvrName;
6721     const char* pDspName;
6722 };
6723 
6724 }
6725 
6726 const ClsIDs aClsIDs[] = {
6727 
6728     { 0x000212F0, "MSWordArt",          "Microsoft Word Art"            },
6729     { 0x000212F0, "MSWordArt.2",        "Microsoft Word Art 2.0"        },
6730 
6731     // MS Apps
6732     { 0x00030000, "ExcelWorksheet",     "Microsoft Excel Worksheet"     },
6733     { 0x00030001, "ExcelChart",         "Microsoft Excel Chart"         },
6734     { 0x00030002, "ExcelMacrosheet",    "Microsoft Excel Macro"         },
6735     { 0x00030003, "WordDocument",       "Microsoft Word Document"       },
6736     { 0x00030004, "MSPowerPoint",       "Microsoft PowerPoint"          },
6737     { 0x00030005, "MSPowerPointSho",    "Microsoft PowerPoint Slide Show"},
6738     { 0x00030006, "MSGraph",            "Microsoft Graph"               },
6739     { 0x00030007, "MSDraw",             "Microsoft Draw"                },
6740     { 0x00030008, "Note-It",            "Microsoft Note-It"             },
6741     { 0x00030009, "WordArt",            "Microsoft Word Art"            },
6742     { 0x0003000a, "PBrush",             "Microsoft PaintBrush Picture"  },
6743     { 0x0003000b, "Equation",           "Microsoft Equation Editor"     },
6744     { 0x0003000c, "Package",            "Package"                       },
6745     { 0x0003000d, "SoundRec",           "Sound"                         },
6746     { 0x0003000e, "MPlayer",            "Media Player"                  },
6747     // MS Demos
6748     { 0x0003000f, "ServerDemo",         "OLE 1.0 Server Demo"           },
6749     { 0x00030010, "Srtest",             "OLE 1.0 Test Demo"             },
6750     { 0x00030011, "SrtInv",             "OLE 1.0 Inv Demo"              },
6751     { 0x00030012, "OleDemo",            "OLE 1.0 Demo"                  },
6752 
6753     // Coromandel / Dorai Swamy / 718-793-7963
6754     { 0x00030013, "CoromandelIntegra",  "Coromandel Integra"            },
6755     { 0x00030014, "CoromandelObjServer","Coromandel Object Server"      },
6756 
6757     // 3-d Visions Corp / Peter Hirsch / 310-325-1339
6758     { 0x00030015, "StanfordGraphics",   "Stanford Graphics"             },
6759 
6760     // Deltapoint / Nigel Hearne / 408-648-4000
6761     { 0x00030016, "DGraphCHART",        "DeltaPoint Graph Chart"        },
6762     { 0x00030017, "DGraphDATA",         "DeltaPoint Graph Data"         },
6763 
6764     // Corel / Richard V. Woodend / 613-728-8200 x1153
6765     { 0x00030018, "PhotoPaint",         "Corel PhotoPaint"              },
6766     { 0x00030019, "CShow",              "Corel Show"                    },
6767     { 0x0003001a, "CorelChart",         "Corel Chart"                   },
6768     { 0x0003001b, "CDraw",              "Corel Draw"                    },
6769 
6770     // Inset Systems / Mark Skiba / 203-740-2400
6771     { 0x0003001c, "HJWIN1.0",           "Inset Systems"                 },
6772 
6773     // Mark V Systems / Mark McGraw / 818-995-7671
6774     { 0x0003001d, "ObjMakerOLE",        "MarkV Systems Object Maker"    },
6775 
6776     // IdentiTech / Mike Gilger / 407-951-9503
6777     { 0x0003001e, "FYI",                "IdentiTech FYI"                },
6778     { 0x0003001f, "FYIView",            "IdentiTech FYI Viewer"         },
6779 
6780     // Inventa Corporation / Balaji Varadarajan / 408-987-0220
6781     { 0x00030020, "Stickynote",         "Inventa Sticky Note"           },
6782 
6783     // ShapeWare Corp. / Lori Pearce / 206-467-6723
6784     { 0x00030021, "ShapewareVISIO10",   "Shapeware Visio 1.0"           },
6785     { 0x00030022, "ImportServer",       "Spaheware Import Server"       },
6786 
6787     // test app SrTest
6788     { 0x00030023, "SrvrTest",           "OLE 1.0 Server Test"           },
6789 
6790     // test app ClTest.  Doesn't really work as a server but is in reg db
6791     { 0x00030025, "Cltest",             "OLE 1.0 Client Test"           },
6792 
6793     // Microsoft ClipArt Gallery   Sherry Larsen-Holmes
6794     { 0x00030026, "MS_ClipArt_Gallery", "Microsoft ClipArt Gallery"     },
6795     // Microsoft Project  Cory Reina
6796     { 0x00030027, "MSProject",          "Microsoft Project"             },
6797 
6798     // Microsoft Works Chart
6799     { 0x00030028, "MSWorksChart",       "Microsoft Works Chart"         },
6800 
6801     // Microsoft Works Spreadsheet
6802     { 0x00030029, "MSWorksSpreadsheet", "Microsoft Works Spreadsheet"   },
6803 
6804     // AFX apps - Dean McCrory
6805     { 0x0003002A, "MinSvr",             "AFX Mini Server"               },
6806     { 0x0003002B, "HierarchyList",      "AFX Hierarchy List"            },
6807     { 0x0003002C, "BibRef",             "AFX BibRef"                    },
6808     { 0x0003002D, "MinSvrMI",           "AFX Mini Server MI"            },
6809     { 0x0003002E, "TestServ",           "AFX Test Server"               },
6810 
6811     // Ami Pro
6812     { 0x0003002F, "AmiProDocument",     "Ami Pro Document"              },
6813 
6814     // WordPerfect Presentations For Windows
6815     { 0x00030030, "WPGraphics",         "WordPerfect Presentation"      },
6816     { 0x00030031, "WPCharts",           "WordPerfect Chart"             },
6817 
6818     // MicroGrafx Charisma
6819     { 0x00030032, "Charisma",           "MicroGrafx Charisma"           },
6820     { 0x00030033, "Charisma_30",        "MicroGrafx Charisma 3.0"       },
6821     { 0x00030034, "CharPres_30",        "MicroGrafx Charisma 3.0 Pres"  },
6822     // MicroGrafx Draw
6823     { 0x00030035, "Draw",               "MicroGrafx Draw"               },
6824     // MicroGrafx Designer
6825     { 0x00030036, "Designer_40",        "MicroGrafx Designer 4.0"       },
6826 
6827     // STAR DIVISION
6828     { 0x00043AD2, "FontWork",           "Star FontWork"                 },
6829 
6830     { 0, "", "" } };
6831 
6832 
6833 bool SvxMSDffManager::ConvertToOle2( SvStream& rStm, sal_uInt32 nReadLen,
6834                     const GDIMetaFile * pMtf, const tools::SvRef<SotStorage>& rDest )
6835 {
6836     bool bMtfRead = false;
6837     tools::SvRef<SotStorageStream> xOle10Stm = rDest->OpenSotStream( "\1Ole10Native",
6838                                                     StreamMode::WRITE| StreamMode::SHARE_DENYALL );
6839     if( xOle10Stm->GetError() )
6840         return false;
6841 
6842     OUString   aSvrName;
6843     sal_uInt32 nDummy0;
6844     sal_uInt32 nDummy1;
6845     sal_uInt32 nBytesRead = 0;
6846     do
6847     {
6848         sal_uInt32 nType(0);
6849         sal_uInt32 nRecType(0);
6850         sal_uInt32 nStrLen(0);
6851 
6852         rStm.ReadUInt32( nType );
6853         rStm.ReadUInt32( nRecType );
6854         rStm.ReadUInt32( nStrLen );
6855         if( nStrLen )
6856         {
6857             if( 0x10000L > nStrLen )
6858             {
6859                 std::unique_ptr<char[]> pBuf(new char[ nStrLen ]);
6860                 rStm.ReadBytes(pBuf.get(), nStrLen);
6861                 aSvrName = OUString( pBuf.get(), static_cast<sal_uInt16>(nStrLen)-1, osl_getThreadTextEncoding() );
6862             }
6863             else
6864                 break;
6865         }
6866         rStm.ReadUInt32( nDummy0 );
6867         rStm.ReadUInt32( nDummy1 );
6868         sal_uInt32 nDataLen(0);
6869         rStm.ReadUInt32( nDataLen );
6870 
6871         nBytesRead += 6 * sizeof( sal_uInt32 ) + nStrLen + nDataLen;
6872 
6873         if (rStm.good() && nReadLen > nBytesRead && nDataLen)
6874         {
6875             if( xOle10Stm.is() )
6876             {
6877                 std::unique_ptr<sal_uInt8[]> pData(new sal_uInt8[ nDataLen ]);
6878                 rStm.ReadBytes(pData.get(), nDataLen);
6879 
6880                 // write to ole10 stream
6881                 xOle10Stm->WriteUInt32( nDataLen );
6882                 xOle10Stm->WriteBytes(pData.get(), nDataLen);
6883                 xOle10Stm = tools::SvRef<SotStorageStream>();
6884 
6885                 // set the compobj stream
6886                 const ClsIDs* pIds;
6887                 for( pIds = aClsIDs; pIds->nId; pIds++ )
6888                 {
6889                     if( aSvrName == OUString::createFromAscii(pIds->pSvrName) )
6890                         break;
6891                 }
6892 
6893                 if( pIds->nId )
6894                 {
6895                     // found!
6896                     SotClipboardFormatId nCbFmt = SotExchange::RegisterFormatName( aSvrName );
6897                     rDest->SetClass( SvGlobalName( pIds->nId, 0, 0, 0xc0,0,0,0,0,0,0,0x46 ), nCbFmt,
6898                                     OUString::createFromAscii( pIds->pDspName ) );
6899                 }
6900                 else
6901                 {
6902                     SotClipboardFormatId nCbFmt = SotExchange::RegisterFormatName( aSvrName );
6903                     rDest->SetClass( SvGlobalName(), nCbFmt, aSvrName );
6904                 }
6905             }
6906             else if( nRecType == 5 && !pMtf )
6907             {
6908                 sal_uInt64 nPos = rStm.Tell();
6909                 sal_uInt16 sz[4];
6910                 rStm.ReadBytes( sz, 8 );
6911                 Graphic aGraphic;
6912                 if( ERRCODE_NONE == GraphicConverter::Import( rStm, aGraphic ) && aGraphic.GetType() != GraphicType::NONE )
6913                 {
6914                     const GDIMetaFile& rMtf = aGraphic.GetGDIMetaFile();
6915                     MakeContentStream( rDest.get(), rMtf );
6916                     bMtfRead = true;
6917                 }
6918                 // set behind the data
6919                 rStm.Seek( nPos + nDataLen );
6920             }
6921             else
6922                 rStm.SeekRel( nDataLen );
6923         }
6924     } while (rStm.good() && nReadLen >= nBytesRead);
6925 
6926     if( !bMtfRead && pMtf )
6927     {
6928         MakeContentStream( rDest.get(), *pMtf );
6929         return true;
6930     }
6931 
6932     return false;
6933 }
6934 
6935 static const char* GetInternalServerName_Impl( const SvGlobalName& aGlobName )
6936 {
6937     if ( aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_60 )
6938       || aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 ) )
6939         return "swriter";
6940     else if ( aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_60 )
6941       || aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 ) )
6942         return "scalc";
6943     else if ( aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_60 )
6944       || aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ) )
6945         return "simpress";
6946     else if ( aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_60 )
6947       || aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 ) )
6948         return "sdraw";
6949     else if ( aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_60 )
6950       || aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 ) )
6951         return "smath";
6952     else if ( aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_60 )
6953       || aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 ) )
6954         return "schart";
6955     return nullptr;
6956 }
6957 
6958 OUString SvxMSDffManager::GetFilterNameFromClassID( const SvGlobalName& aGlobName )
6959 {
6960     if ( aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_60 ) )
6961         return "StarOffice XML (Writer)";
6962 
6963     if ( aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 ) )
6964         return "writer8";
6965 
6966     if ( aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_60 ) )
6967         return "StarOffice XML (Calc)";
6968 
6969     if ( aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 ) )
6970         return "calc8";
6971 
6972     if ( aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_60 ) )
6973         return "StarOffice XML (Impress)";
6974 
6975     if ( aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ) )
6976         return "impress8";
6977 
6978     if ( aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_60 ) )
6979         return "StarOffice XML (Draw)";
6980 
6981     if ( aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 ) )
6982         return "draw8";
6983 
6984     if ( aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_60 ) )
6985         return "StarOffice XML (Math)";
6986 
6987     if ( aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 ) )
6988         return "math8";
6989 
6990     if ( aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_60 ) )
6991         return "StarOffice XML (Chart)";
6992 
6993     if ( aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 ) )
6994         return "chart8";
6995 
6996     return OUString();
6997 }
6998 
6999 void SvxMSDffManager::ExtractOwnStream(SotStorage& rSrcStg, SvMemoryStream& rMemStream)
7000 {
7001     tools::SvRef<SotStorageStream> xStr
7002         = rSrcStg.OpenSotStream("package_stream", StreamMode::STD_READ);
7003     xStr->ReadStream(rMemStream);
7004 }
7005 
7006 css::uno::Reference < css::embed::XEmbeddedObject >  SvxMSDffManager::CheckForConvertToSOObj( sal_uInt32 nConvertFlags,
7007                         SotStorage& rSrcStg, const uno::Reference < embed::XStorage >& rDestStorage,
7008                         const Graphic& rGrf,
7009                         const tools::Rectangle& rVisArea, OUString const& rBaseURL)
7010 {
7011     uno::Reference < embed::XEmbeddedObject > xObj;
7012     SvGlobalName aStgNm = rSrcStg.GetClassName();
7013     const char* pName = GetInternalServerName_Impl( aStgNm );
7014     OUString sStarName;
7015     if ( pName )
7016         sStarName = OUString::createFromAscii( pName );
7017     else if ( nConvertFlags )
7018     {
7019         static struct ObjImpType
7020         {
7021             sal_uInt32 nFlag;
7022             const char* pFactoryNm;
7023             // GlobalNameId
7024             sal_uInt32 n1;
7025             sal_uInt16 n2, n3;
7026             sal_uInt8 b8, b9, b10, b11, b12, b13, b14, b15;
7027         } const aArr[] = {
7028             { OLE_MATHTYPE_2_STARMATH, "smath", MSO_EQUATION3_CLASSID },
7029             { OLE_MATHTYPE_2_STARMATH, "smath", MSO_EQUATION2_CLASSID },
7030             { OLE_WINWORD_2_STARWRITER, "swriter", MSO_WW8_CLASSID },
7031             // Excel table
7032             { OLE_EXCEL_2_STARCALC, "scalc", MSO_EXCEL5_CLASSID },
7033             { OLE_EXCEL_2_STARCALC, "scalc", MSO_EXCEL8_CLASSID },
7034             // 114465: additional Excel OLE chart classId to above.
7035             { OLE_EXCEL_2_STARCALC, "scalc", MSO_EXCEL8_CHART_CLASSID },
7036             // PowerPoint presentation
7037             { OLE_POWERPOINT_2_STARIMPRESS, "simpress", MSO_PPT8_CLASSID },
7038             // PowerPoint slide
7039             { OLE_POWERPOINT_2_STARIMPRESS, "simpress", MSO_PPT8_SLIDE_CLASSID },
7040             { 0, nullptr,
7041               0, 0, 0,
7042               0, 0, 0, 0, 0, 0, 0, 0 }
7043         };
7044 
7045         for( const ObjImpType* pArr = aArr; pArr->nFlag; ++pArr )
7046         {
7047             if( nConvertFlags & pArr->nFlag )
7048             {
7049                 SvGlobalName aTypeName( pArr->n1, pArr->n2, pArr->n3,
7050                                 pArr->b8, pArr->b9, pArr->b10, pArr->b11,
7051                                 pArr->b12, pArr->b13, pArr->b14, pArr->b15 );
7052 
7053                 if ( aStgNm == aTypeName )
7054                 {
7055                     sStarName = OUString::createFromAscii( pArr->pFactoryNm );
7056                     break;
7057                 }
7058             }
7059         }
7060     }
7061 
7062     if ( sStarName.getLength() )
7063     {
7064         //TODO/MBA: check if (and when) storage and stream will be destroyed!
7065         std::shared_ptr<const SfxFilter> pFilter;
7066         std::unique_ptr<SvMemoryStream> xMemStream (new SvMemoryStream);
7067         if ( pName )
7068         {
7069             // TODO/LATER: perhaps we need to retrieve VisArea and Metafile from the storage also
7070             SvxMSDffManager::ExtractOwnStream(rSrcStg, *xMemStream);
7071         }
7072         else
7073         {
7074             SfxFilterMatcher aMatch( sStarName );
7075             tools::SvRef<SotStorage> xStorage = new SotStorage( false, *xMemStream );
7076             rSrcStg.CopyTo( xStorage.get() );
7077             xStorage->Commit();
7078             xStorage.clear();
7079             OUString aType = SfxFilter::GetTypeFromStorage( rSrcStg );
7080             if (aType.getLength() && !utl::ConfigManager::IsFuzzing())
7081                 pFilter = aMatch.GetFilter4EA( aType );
7082         }
7083 
7084 #ifdef DEBUG_FILTER_MSFILTER
7085         // extract embedded ole streams into "/tmp/embedded_stream_NNN"
7086         static sal_Int32 nOleCount(0);
7087         OUString aTmpName("/tmp/embedded_stream_");
7088         aTmpName += OUString::number(nOleCount++);
7089         aTmpName += ".bin";
7090         SvFileStream aTmpStream(aTmpName,StreamMode::READ|StreamMode::WRITE|StreamMode::TRUNC);
7091         xMemStream->Seek(0);
7092         aTmpStream.WriteStream(*xMemStream);
7093         aTmpStream.Close();
7094 #endif
7095         if ( pName || pFilter )
7096         {
7097             //Reuse current ole name
7098             OUString aDstStgName = MSO_OLE_Obj + OUString::number(nMSOleObjCntr);
7099 
7100             OUString aFilterName;
7101             if ( pFilter )
7102                 aFilterName = pFilter->GetName();
7103             else
7104                 aFilterName = SvxMSDffManager::GetFilterNameFromClassID( aStgNm );
7105 
7106             uno::Sequence<beans::PropertyValue> aMedium(aFilterName.isEmpty() ? 3 : 4);
7107             aMedium[0].Name = "InputStream";
7108             uno::Reference < io::XInputStream > xStream = new ::utl::OSeekableInputStreamWrapper( *xMemStream );
7109             aMedium[0].Value <<= xStream;
7110             aMedium[1].Name = "URL";
7111             aMedium[1].Value <<= OUString( "private:stream" );
7112             aMedium[2].Name = "DocumentBaseURL";
7113             aMedium[2].Value <<= rBaseURL;
7114 
7115             if ( !aFilterName.isEmpty() )
7116             {
7117                 aMedium[3].Name = "FilterName";
7118                 aMedium[3].Value <<= aFilterName;
7119             }
7120 
7121             OUString aName( aDstStgName );
7122             comphelper::EmbeddedObjectContainer aCnt( rDestStorage );
7123             xObj = aCnt.InsertEmbeddedObject(aMedium, aName, &rBaseURL);
7124 
7125             if ( !xObj.is() )
7126             {
7127                 if( !aFilterName.isEmpty() )
7128                 {
7129                     // throw the filter parameter away as workaround
7130                     aMedium.realloc( 2 );
7131                     xObj = aCnt.InsertEmbeddedObject(aMedium, aName, &rBaseURL);
7132                 }
7133 
7134                 if ( !xObj.is() )
7135                      return xObj;
7136             }
7137 
7138             // JP 26.10.2001: Bug 93374 / 91928 the writer
7139             // objects need the correct visarea needs the
7140             // correct visarea, but this is not true for
7141             // PowerPoint (see bugdoc 94908b)
7142             // SJ: 19.11.2001 bug 94908, also chart objects
7143             // needs the correct visarea
7144 
7145             // If pName is set this is an own embedded object, it should have the correct size internally
7146             // TODO/LATER: it might make sense in future to set the size stored in internal object
7147             if( !pName && ( sStarName == "swriter" || sStarName == "scalc" ) )
7148             {
7149                 // TODO/LATER: ViewAspect must be passed from outside!
7150                 sal_Int64 nViewAspect = embed::Aspects::MSOLE_CONTENT;
7151                 MapMode aMapMode( VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nViewAspect ) ) );
7152                 Size aSz;
7153                 if ( rVisArea.IsEmpty() )
7154                     aSz = lcl_GetPrefSize(rGrf, aMapMode );
7155                 else
7156                 {
7157                     aSz = rVisArea.GetSize();
7158                     aSz = OutputDevice::LogicToLogic( aSz, MapMode( MapUnit::Map100thMM ), aMapMode );
7159                 }
7160 
7161                 // don't modify the object
7162                 //TODO/LATER: remove those hacks, that needs to be done differently!
7163                 //xIPObj->EnableSetModified( sal_False );
7164                 awt::Size aSize;
7165                 aSize.Width = aSz.Width();
7166                 aSize.Height = aSz.Height();
7167                 xObj->setVisualAreaSize( nViewAspect, aSize );
7168                 //xIPObj->EnableSetModified( sal_True );
7169             }
7170             else if ( sStarName == "smath" )
7171             {   // SJ: force the object to recalc its visarea
7172                 //TODO/LATER: wait for PrinterChangeNotification
7173                 //xIPObj->OnDocumentPrinterChanged( NULL );
7174             }
7175         }
7176     }
7177 
7178     return xObj;
7179 }
7180 
7181 // TODO/MBA: code review and testing!
7182 SdrOle2Obj* SvxMSDffManager::CreateSdrOLEFromStorage(
7183     SdrModel& rSdrModel,
7184     const OUString& rStorageName,
7185     tools::SvRef<SotStorage> const & rSrcStorage,
7186     const uno::Reference < embed::XStorage >& xDestStorage,
7187     const Graphic& rGrf,
7188     const tools::Rectangle& rBoundRect,
7189     const tools::Rectangle& rVisArea,
7190     SvStream* pDataStrm,
7191     ErrCode& rError,
7192     sal_uInt32 nConvertFlags,
7193     sal_Int64 nRecommendedAspect,
7194     OUString const& rBaseURL)
7195 {
7196     sal_Int64 nAspect = nRecommendedAspect;
7197     SdrOle2Obj* pRet = nullptr;
7198     if( rSrcStorage.is() && xDestStorage.is() && rStorageName.getLength() )
7199     {
7200         comphelper::EmbeddedObjectContainer aCnt( xDestStorage );
7201         // does the 01Ole-Stream exist at all?
7202         // (that's not the case for e.g. Fontwork )
7203         // If that's not the case -> include it as graphic
7204         bool bValidStorage = false;
7205         OUString aDstStgName = MSO_OLE_Obj + OUString::number( ++nMSOleObjCntr );
7206 
7207         {
7208             tools::SvRef<SotStorage> xObjStg = rSrcStorage->OpenSotStorage( rStorageName );
7209             if( xObjStg.is()  )
7210             {
7211                 {
7212                     sal_uInt8 aTestA[10];   // exist the \1CompObj-Stream ?
7213                     tools::SvRef<SotStorageStream> xSrcTst = xObjStg->OpenSotStream( "\1CompObj" );
7214                     bValidStorage = xSrcTst.is() && sizeof( aTestA ) ==
7215                                     xSrcTst->ReadBytes(aTestA, sizeof(aTestA));
7216                     if( !bValidStorage )
7217                     {
7218                         // or the \1Ole-Stream ?
7219                         xSrcTst = xObjStg->OpenSotStream( "\1Ole" );
7220                         bValidStorage = xSrcTst.is() && sizeof(aTestA) ==
7221                                     xSrcTst->ReadBytes(aTestA, sizeof(aTestA));
7222                     }
7223                 }
7224 
7225                 if( bValidStorage )
7226                 {
7227                     if ( nAspect != embed::Aspects::MSOLE_ICON )
7228                     {
7229                         // check whether the object is iconified one
7230                         // usually this information is already known, the only exception
7231                         // is a kind of embedded objects in Word documents
7232                         // TODO/LATER: should the caller be notified if the aspect changes in future?
7233 
7234                         tools::SvRef<SotStorageStream> xObjInfoSrc = xObjStg->OpenSotStream(
7235                             "\3ObjInfo", StreamMode::STD_READ );
7236                         if ( xObjInfoSrc.is() && !xObjInfoSrc->GetError() )
7237                         {
7238                             sal_uInt8 nByte = 0;
7239                             xObjInfoSrc->ReadUChar( nByte );
7240                             if ( ( nByte >> 4 ) & embed::Aspects::MSOLE_ICON )
7241                                 nAspect = embed::Aspects::MSOLE_ICON;
7242                         }
7243                     }
7244 
7245                     uno::Reference < embed::XEmbeddedObject > xObj( CheckForConvertToSOObj(
7246                             nConvertFlags, *xObjStg, xDestStorage, rGrf,
7247                             rVisArea, rBaseURL));
7248                     if ( xObj.is() )
7249                     {
7250                         // remember file name to use in the title bar
7251                         INetURLObject aURL(rBaseURL);
7252                         xObj->setContainerName(aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset));
7253 
7254                         svt::EmbeddedObjectRef aObj( xObj, nAspect );
7255 
7256                         // TODO/LATER: need MediaType
7257                         aObj.SetGraphic( rGrf, OUString() );
7258 
7259                         // TODO/MBA: check setting of PersistName
7260                         pRet = new SdrOle2Obj(
7261                             rSdrModel,
7262                             aObj,
7263                             OUString(),
7264                             rBoundRect);
7265 
7266                         // we have the Object, don't create another
7267                         bValidStorage = false;
7268                     }
7269                 }
7270             }
7271         }
7272 
7273         if( bValidStorage )
7274         {
7275             // object is not an own object
7276             tools::SvRef<SotStorage> xObjStor = SotStorage::OpenOLEStorage( xDestStorage, aDstStgName, StreamMode::READWRITE );
7277 
7278             if ( xObjStor.is() )
7279             {
7280                 tools::SvRef<SotStorage> xSrcStor = rSrcStorage->OpenSotStorage( rStorageName, StreamMode::READ );
7281                 xSrcStor->CopyTo( xObjStor.get() );
7282 
7283                 if( !xObjStor->GetError() )
7284                     xObjStor->Commit();
7285 
7286                 if( xObjStor->GetError() )
7287                 {
7288                     rError = xObjStor->GetError();
7289                     bValidStorage = false;
7290                 }
7291                 else if( !xObjStor.is() )
7292                     bValidStorage = false;
7293             }
7294         }
7295         else if( pDataStrm )
7296         {
7297             sal_uInt32 nLen(0), nDummy(0);
7298             pDataStrm->ReadUInt32( nLen ).ReadUInt32( nDummy );
7299             if( ERRCODE_NONE != pDataStrm->GetError() ||
7300                 // Id in BugDoc - exist there other Ids?
7301                 // The ConvertToOle2 - does not check for consistent
7302                 0x30008 != nDummy )
7303                 bValidStorage = false;
7304             else
7305             {
7306                 // or is it an OLE-1 Stream in the DataStream?
7307                 tools::SvRef<SotStorage> xObjStor = SotStorage::OpenOLEStorage( xDestStorage, aDstStgName );
7308                 //TODO/MBA: remove metafile conversion from ConvertToOle2
7309                 //when is this code used?!
7310                 GDIMetaFile aMtf;
7311                 bValidStorage = ConvertToOle2( *pDataStrm, nLen, &aMtf, xObjStor );
7312                 xObjStor->Commit();
7313             }
7314         }
7315 
7316         if( bValidStorage )
7317         {
7318             uno::Reference < embed::XEmbeddedObject > xObj = aCnt.GetEmbeddedObject( aDstStgName );
7319             if( xObj.is() )
7320             {
7321                 // remember file name to use in the title bar
7322                 INetURLObject aURL( rBaseURL );
7323                 xObj->setContainerName( aURL.GetLastName( INetURLObject::DecodeMechanism::WithCharset ) );
7324 
7325                 // the visual area must be retrieved from the metafile (object doesn't know it so far)
7326 
7327                 if ( nAspect != embed::Aspects::MSOLE_ICON )
7328                 {
7329                     // working with visual area can switch the object to running state
7330                     try
7331                     {
7332                         awt::Size aAwtSz;
7333                         // the provided visual area should be used, if there is any
7334                         if ( rVisArea.IsEmpty() )
7335                         {
7336                             MapUnit aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
7337                             Size aSz(lcl_GetPrefSize(rGrf, MapMode(aMapUnit)));
7338                             aAwtSz.Width = aSz.Width();
7339                             aAwtSz.Height = aSz.Height();
7340                         }
7341                         else
7342                         {
7343                             aAwtSz.Width = rVisArea.GetWidth();
7344                             aAwtSz.Height = rVisArea.GetHeight();
7345                         }
7346                         //xInplaceObj->EnableSetModified( sal_False );
7347                         xObj->setVisualAreaSize( nAspect, aAwtSz );
7348                         //xInplaceObj->EnableSetModified( sal_True );
7349                     }
7350                     catch( const uno::Exception& )
7351                     {
7352                         OSL_FAIL( "Could not set visual area of the object!" );
7353                     }
7354                 }
7355 
7356                 svt::EmbeddedObjectRef aObj( xObj, nAspect );
7357 
7358                 // TODO/LATER: need MediaType
7359                 aObj.SetGraphic( rGrf, OUString() );
7360 
7361                 pRet = new SdrOle2Obj(
7362                     rSdrModel,
7363                     aObj,
7364                     aDstStgName,
7365                     rBoundRect);
7366             }
7367         }
7368     }
7369 
7370     return pRet;
7371 }
7372 
7373 bool SvxMSDffManager::SetPropValue( const uno::Any& rAny, const uno::Reference< css::beans::XPropertySet > & rXPropSet,
7374             const OUString& rPropName )
7375 {
7376     bool bRetValue = false;
7377     try
7378     {
7379         uno::Reference< beans::XPropertySetInfo >
7380             aXPropSetInfo( rXPropSet->getPropertySetInfo() );
7381         if ( aXPropSetInfo.is() )
7382             bRetValue = aXPropSetInfo->hasPropertyByName( rPropName );
7383     }
7384     catch( const uno::Exception& )
7385     {
7386         bRetValue = false;
7387     }
7388     if ( bRetValue )
7389     {
7390         try
7391         {
7392             rXPropSet->setPropertyValue( rPropName, rAny );
7393             bRetValue = true;
7394         }
7395         catch( const uno::Exception& )
7396         {
7397             bRetValue = false;
7398         }
7399     }
7400     return bRetValue;
7401 }
7402 
7403 SvxMSDffImportRec::SvxMSDffImportRec()
7404     : pObj( nullptr ),
7405       nClientAnchorLen(  0 ),
7406       nClientDataLen(    0 ),
7407       nXAlign( 0 ), // position n cm from left
7408       nYAlign( 0 ), // position n cm below
7409       nLayoutInTableCell( 0 ), // element is laid out in table cell
7410       nFlags( ShapeFlag::NONE ),
7411       nDxTextLeft( 144 ),
7412       nDyTextTop( 72 ),
7413       nDxTextRight( 144 ),
7414       nDyTextBottom( 72 ),
7415       nDxWrapDistLeft( 0 ),
7416       nDyWrapDistTop( 0 ),
7417       nDxWrapDistRight( 0 ),
7418       nDyWrapDistBottom(0 ),
7419       nCropFromTop( 0 ),
7420       nCropFromBottom( 0 ),
7421       nCropFromLeft( 0 ),
7422       nCropFromRight( 0 ),
7423       aTextId(),
7424       nNextShapeId( 0 ),
7425       nShapeId( 0 ),
7426       eShapeType( mso_sptNil ),
7427       relativeHorizontalWidth( -1 ),
7428       isHorizontalRule( false )
7429 {
7430       eLineStyle      = mso_lineSimple; // GPF-Bug #66227#
7431       eLineDashing    = mso_lineSolid;
7432       bDrawHell       = false;
7433       bHidden         = false;
7434 
7435       bReplaceByFly   = false;
7436       bVFlip          = false;
7437       bHFlip          = false;
7438       bAutoWidth      = false;
7439 }
7440 
7441 SvxMSDffImportRec::SvxMSDffImportRec(const SvxMSDffImportRec& rCopy)
7442     : pObj( rCopy.pObj ),
7443       nXAlign( rCopy.nXAlign ),
7444       nXRelTo( rCopy.nXRelTo ),
7445       nYAlign( rCopy.nYAlign ),
7446       nYRelTo( rCopy.nYRelTo ),
7447       nLayoutInTableCell( rCopy.nLayoutInTableCell ),
7448       nFlags( rCopy.nFlags ),
7449       nDxTextLeft( rCopy.nDxTextLeft    ),
7450       nDyTextTop( rCopy.nDyTextTop ),
7451       nDxTextRight( rCopy.nDxTextRight ),
7452       nDyTextBottom( rCopy.nDyTextBottom ),
7453       nDxWrapDistLeft( rCopy.nDxWrapDistLeft ),
7454       nDyWrapDistTop( rCopy.nDyWrapDistTop ),
7455       nDxWrapDistRight( rCopy.nDxWrapDistRight ),
7456       nDyWrapDistBottom(rCopy.nDyWrapDistBottom ),
7457       nCropFromTop( rCopy.nCropFromTop ),
7458       nCropFromBottom( rCopy.nCropFromBottom ),
7459       nCropFromLeft( rCopy.nCropFromLeft ),
7460       nCropFromRight( rCopy.nCropFromRight ),
7461       aTextId( rCopy.aTextId ),
7462       nNextShapeId( rCopy.nNextShapeId ),
7463       nShapeId( rCopy.nShapeId ),
7464       eShapeType( rCopy.eShapeType ),
7465       relativeHorizontalWidth( rCopy.relativeHorizontalWidth ),
7466       isHorizontalRule( rCopy.isHorizontalRule )
7467 {
7468     eLineStyle       = rCopy.eLineStyle; // GPF-Bug #66227#
7469     eLineDashing     = rCopy.eLineDashing;
7470     bDrawHell        = rCopy.bDrawHell;
7471     bHidden          = rCopy.bHidden;
7472     bReplaceByFly    = rCopy.bReplaceByFly;
7473     bAutoWidth       = rCopy.bAutoWidth;
7474     bVFlip = rCopy.bVFlip;
7475     bHFlip = rCopy.bHFlip;
7476     nClientAnchorLen = rCopy.nClientAnchorLen;
7477     if( rCopy.nClientAnchorLen )
7478     {
7479         pClientAnchorBuffer.reset( new char[ nClientAnchorLen ] );
7480         memcpy( pClientAnchorBuffer.get(),
7481                 rCopy.pClientAnchorBuffer.get(),
7482                 nClientAnchorLen );
7483     }
7484     else
7485         pClientAnchorBuffer = nullptr;
7486 
7487     nClientDataLen = rCopy.nClientDataLen;
7488     if( rCopy.nClientDataLen )
7489     {
7490         pClientDataBuffer.reset( new char[ nClientDataLen ] );
7491         memcpy( pClientDataBuffer.get(),
7492                 rCopy.pClientDataBuffer.get(),
7493                 nClientDataLen );
7494     }
7495     else
7496         pClientDataBuffer = nullptr;
7497 
7498     if (rCopy.pWrapPolygon)
7499         pWrapPolygon.reset( new tools::Polygon(*rCopy.pWrapPolygon) );
7500 }
7501 
7502 SvxMSDffImportRec::~SvxMSDffImportRec()
7503 {
7504 }
7505 
7506 void SvxMSDffManager::insertShapeId( sal_Int32 nShapeId, SdrObject* pShape )
7507 {
7508     maShapeIdContainer[nShapeId] = pShape;
7509 }
7510 
7511 void SvxMSDffManager::removeShapeId( SdrObject const * pShape )
7512 {
7513     SvxMSDffShapeIdContainer::iterator aIter = std::find_if(maShapeIdContainer.begin(), maShapeIdContainer.end(),
7514         [&pShape](const SvxMSDffShapeIdContainer::value_type& rEntry) { return rEntry.second == pShape; });
7515     if (aIter != maShapeIdContainer.end())
7516         maShapeIdContainer.erase( aIter );
7517 }
7518 
7519 SdrObject* SvxMSDffManager::getShapeForId( sal_Int32 nShapeId )
7520 {
7521     SvxMSDffShapeIdContainer::iterator aIter( maShapeIdContainer.find(nShapeId) );
7522     return aIter != maShapeIdContainer.end() ? (*aIter).second : nullptr;
7523 }
7524 
7525 SvxMSDffImportData::SvxMSDffImportData(const tools::Rectangle& rParentRect)
7526     : aParentRect(rParentRect)
7527 {
7528 }
7529 
7530 SvxMSDffImportData::~SvxMSDffImportData()
7531 {
7532 }
7533 
7534 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
7535