related tdf#162786: Add cacert.pem
[LibreOffice.git] / filter / source / msfilter / msdffimp.cxx
blob3d1d45b509b109973ac8b8c373486b017f3d50e6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/embed/Aspects.hpp>
21 #include <com/sun/star/embed/XEmbeddedObject.hpp>
23 #include <math.h>
24 #include <limits>
25 #include <limits.h>
26 #include <utility>
27 #include <vector>
29 #include <o3tl/any.hxx>
30 #include <o3tl/safeint.hxx>
31 #include <osl/file.hxx>
32 #include <tools/solar.h>
33 #include <sal/log.hxx>
34 #include <rtl/math.hxx>
36 #include <comphelper/classids.hxx>
37 #include <toolkit/helper/vclunohelper.hxx>
38 #include <comphelper/configuration.hxx>
39 #include <unotools/streamwrap.hxx>
40 #include <comphelper/processfactory.hxx>
41 #include <comphelper/string.hxx>
42 #include <comphelper/seqstream.hxx>
43 #include <comphelper/storagehelper.hxx>
44 #include <comphelper/sequence.hxx>
45 #include <sot/exchange.hxx>
46 #include <sot/storinfo.hxx>
47 #include <vcl/cvtgrf.hxx>
48 #include <vcl/wmf.hxx>
49 #include <vcl/settings.hxx>
50 #include <vcl/vclptr.hxx>
51 #include <vcl/BitmapTools.hxx>
52 #include "viscache.hxx"
54 // SvxItem-Mapping. Is needed to successfully include the SvxItem-Header
55 #include <editeng/eeitem.hxx>
56 #include <editeng/editdata.hxx>
57 #include <tools/bigint.hxx>
58 #include <tools/debug.hxx>
59 #include <tools/stream.hxx>
60 #include <tools/zcodec.hxx>
61 #include <filter/msfilter/escherex.hxx>
62 #include <basegfx/numeric/ftools.hxx>
63 #include <basegfx/polygon/b2dpolygontools.hxx>
64 #include <com/sun/star/drawing/Position3D.hpp>
65 #include <com/sun/star/drawing/Direction3D.hpp>
66 #include <editeng/charscaleitem.hxx>
67 #include <editeng/kernitem.hxx>
68 #include <vcl/graphicfilter.hxx>
69 #include <tools/urlobj.hxx>
70 #include <vcl/virdev.hxx>
71 #include <vcl/BitmapReadAccess.hxx>
72 #include <sot/storage.hxx>
73 #include <sfx2/docfilt.hxx>
74 #include <sfx2/fcontnr.hxx>
75 #include <svx/xbtmpit.hxx>
76 #include <svx/xsflclit.hxx>
77 #include <svx/xfilluseslidebackgrounditem.hxx>
78 #include <svx/xflgrit.hxx>
79 #include <svx/xflftrit.hxx>
80 #include <svx/sdgcpitm.hxx>
81 #include <svx/sdgmoitm.hxx>
82 #include <svx/svdmodel.hxx>
83 #include <svx/svdobj.hxx>
84 #include <svx/svdpage.hxx>
85 #include <svx/svdogrp.hxx>
86 #include <svx/svdograf.hxx>
87 #include <svx/svdotext.hxx>
88 #include <svx/svdorect.hxx>
89 #include <svx/svdoedge.hxx>
90 #include <svx/svdoutl.hxx>
91 #include <svx/svdoole2.hxx>
92 #include <svx/svdopath.hxx>
93 #include <svx/xlntrit.hxx>
94 #include <svx/xfillit0.hxx>
95 #include <svx/xflbmtit.hxx>
96 #include <svx/xflclit.hxx>
97 #include <svx/xfltrit.hxx>
98 #include <svx/xflbmsxy.hxx>
99 #include <svx/xflbmsli.hxx>
100 #include <editeng/frmdir.hxx>
101 #include <editeng/frmdiritem.hxx>
102 #include <svx/svdtrans.hxx>
103 #include <svx/sxenditm.hxx>
104 #include <svx/sdgluitm.hxx>
105 #include <editeng/fhgtitem.hxx>
106 #include <editeng/wghtitem.hxx>
107 #include <editeng/postitem.hxx>
108 #include <editeng/udlnitem.hxx>
109 #include <editeng/crossedoutitem.hxx>
110 #include <editeng/shdditem.hxx>
111 #include <editeng/fontitem.hxx>
112 #include <svx/sxekitm.hxx>
113 #include <svx/xpoly.hxx>
114 #include <svx/xlineit0.hxx>
115 #include <svx/xlncapit.hxx>
116 #include <svx/xlinjoit.hxx>
117 #include <svx/xlndsit.hxx>
118 #include <svx/xlnclit.hxx>
119 #include <svx/xlnwtit.hxx>
120 #include <svx/xlnstwit.hxx>
121 #include <svx/xlnedwit.hxx>
122 #include <svx/xlnstit.hxx>
123 #include <svx/xlnedit.hxx>
124 #include <svx/xlnstcit.hxx>
125 #include <svx/xlnedcit.hxx>
126 #include <svx/sdasitm.hxx>
127 #include <svx/sdggaitm.hxx>
128 #include <svx/sdshcitm.hxx>
129 #include <svx/sdshitm.hxx>
130 #include <svx/sdshtitm.hxx>
131 #include <svx/sdsxyitm.hxx>
132 #include <svx/sdtagitm.hxx>
133 #include <svx/sdtcfitm.hxx>
134 #include <svx/sdtditm.hxx>
135 #include <svx/sdtfsitm.hxx>
136 #include <svx/sdtmfitm.hxx>
137 #include <filter/msfilter/classids.hxx>
138 #include <filter/msfilter/msdffimp.hxx>
139 #include <editeng/outliner.hxx>
140 #include <editeng/outlobj.hxx>
141 #include <com/sun/star/drawing/ShadeMode.hpp>
142 #include <vcl/dibtools.hxx>
143 #include <vcl/svapp.hxx>
144 #include <svx/svdoashp.hxx>
145 #include <svx/EnhancedCustomShapeTypeNames.hxx>
146 #include <svx/EnhancedCustomShapeGeometry.hxx>
147 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
148 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
149 #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
150 #include <com/sun/star/drawing/EnhancedCustomShapeGluePointType.hpp>
151 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
152 #include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
153 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
154 #include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
155 #include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp>
156 #include <com/sun/star/beans/PropertyValues.hpp>
157 #include <com/sun/star/beans/XPropertySetInfo.hpp>
158 #include <com/sun/star/beans/XPropertySet.hpp>
159 #include <com/sun/star/drawing/ProjectionMode.hpp>
160 #include <svx/EnhancedCustomShape2d.hxx>
161 #include <rtl/ustring.hxx>
162 #include <svtools/embedhlp.hxx>
163 #include <memory>
165 using namespace ::com::sun::star ;
166 using namespace ::com::sun::star::drawing;
167 using namespace uno ;
168 using namespace beans ;
169 using namespace drawing ;
170 using namespace container ;
172 // static counter for OLE-Objects
173 static sal_uInt32 nMSOleObjCntr = 0;
174 constexpr OUString MSO_OLE_Obj = u"MSO_OLE_Obj"_ustr;
176 namespace {
177 /* Office File Formats - 2.2.23 */
178 enum class OfficeArtBlipRecInstance : sal_uInt32
180 EMF = 0x3D4, // defined in section 2.2.24.
181 WMF = 0x216, // defined in section 2.2.25.
182 PICT = 0x542, // as defined in section 2.2.26.
183 JPEG_RGB = 0x46A, // defined in section 2.2.27.
184 JPEG_CMYK = 0x6E2, // defined in section 2.2.27.
185 PNG = 0x6E0, // defined in section 2.2.28.
186 DIB = 0x7A8, // defined in section 2.2.29.
187 TIFF = 0x6E4 // defined in section 2.2.30.
190 struct SvxMSDffBLIPInfo
192 sal_uInt32 nFilePos; ///< offset of the BLIP in data stream
193 explicit SvxMSDffBLIPInfo(sal_uInt32 nFPos)
194 : nFilePos(nFPos)
201 /// the following will be sorted by the order of their appearance:
202 struct SvxMSDffBLIPInfos : public std::vector<SvxMSDffBLIPInfo> {};
204 /************************************************************************/
205 void Impl_OlePres::Write( SvStream & rStm )
207 WriteClipboardFormat( rStm, SotClipboardFormatId::GDIMETAFILE );
208 rStm.WriteInt32( 4 ); // a TargetDevice that's always empty
209 rStm.WriteUInt32( nAspect );
210 rStm.WriteInt32( -1 ); //L-Index always -1
211 rStm.WriteInt32( nAdvFlags );
212 rStm.WriteInt32( 0 ); //Compression
213 rStm.WriteInt32( aSize.Width() );
214 rStm.WriteInt32( aSize.Height() );
215 sal_uInt64 nPos = rStm.Tell();
216 rStm.WriteInt32( 0 );
218 if( nFormat == SotClipboardFormatId::GDIMETAFILE && pMtf )
220 // Always to 1/100 mm, until Mtf-Solution found
221 // Assumption (no scaling, no origin translation)
222 DBG_ASSERT( pMtf->GetPrefMapMode().GetScaleX() == Fraction( 1, 1 ),
223 "x-scale in the Mtf is wrong" );
224 DBG_ASSERT( pMtf->GetPrefMapMode().GetScaleY() == Fraction( 1, 1 ),
225 "y-scale in the Mtf is wrong" );
226 DBG_ASSERT( pMtf->GetPrefMapMode().GetOrigin() == Point(),
227 "origin-shift in the Mtf is wrong" );
228 MapUnit nMU = pMtf->GetPrefMapMode().GetMapUnit();
229 if( MapUnit::Map100thMM != nMU )
231 Size aPrefS( pMtf->GetPrefSize() );
232 Size aS = OutputDevice::LogicToLogic(aPrefS, MapMode(nMU), MapMode(MapUnit::Map100thMM));
234 pMtf->Scale( Fraction( aS.Width(), aPrefS.Width() ),
235 Fraction( aS.Height(), aPrefS.Height() ) );
236 pMtf->SetPrefMapMode(MapMode(MapUnit::Map100thMM));
237 pMtf->SetPrefSize( aS );
239 WriteWindowMetafileBits( rStm, *pMtf );
241 else
243 OSL_FAIL( "unknown format" );
245 sal_uInt64 nEndPos = rStm.Tell();
246 rStm.Seek( nPos );
247 rStm.WriteUInt32( nEndPos - nPos - 4 );
248 rStm.Seek( nEndPos );
251 DffPropertyReader::DffPropertyReader( const SvxMSDffManager& rMan )
252 : rManager(rMan)
253 , mnFix16Angle(0)
254 , mbRotateGranientFillWithAngle(false)
256 InitializePropSet( DFF_msofbtOPT );
259 void DffPropertyReader::SetDefaultPropSet( SvStream& rStCtrl, sal_uInt32 nOffsDgg ) const
261 const_cast<DffPropertyReader*>(this)->pDefaultPropSet.reset();
262 sal_uInt64 nOldPos = rStCtrl.Tell();
263 bool bOk = checkSeek(rStCtrl, nOffsDgg);
264 DffRecordHeader aRecHd;
265 if (bOk)
266 bOk = ReadDffRecordHeader( rStCtrl, aRecHd );
267 if (bOk && aRecHd.nRecType == DFF_msofbtDggContainer)
269 if ( SvxMSDffManager::SeekToRec( rStCtrl, DFF_msofbtOPT, aRecHd.GetRecEndFilePos() ) )
271 const_cast<DffPropertyReader*>(this)->pDefaultPropSet.reset( new DffPropSet );
272 ReadDffPropSet( rStCtrl, *pDefaultPropSet );
275 rStCtrl.Seek( nOldPos );
278 #ifdef DBG_CUSTOMSHAPE
279 void DffPropertyReader::ReadPropSet( SvStream& rIn, SvxMSDffClientData* pClientData, sal_uInt32 nShapeId ) const
280 #else
281 void DffPropertyReader::ReadPropSet( SvStream& rIn, SvxMSDffClientData* pClientData ) const
282 #endif
284 sal_uInt64 nFilePos = rIn.Tell();
285 ReadDffPropSet( rIn, const_cast<DffPropertyReader&>(*this) );
287 if ( IsProperty( DFF_Prop_hspMaster ) )
289 if ( rManager.SeekToShape( rIn, pClientData, GetPropertyValue( DFF_Prop_hspMaster, 0 ) ) )
291 DffRecordHeader aRecHd;
292 bool bOk = ReadDffRecordHeader(rIn, aRecHd);
293 if (bOk && SvxMSDffManager::SeekToRec(rIn, DFF_msofbtOPT, aRecHd.GetRecEndFilePos()))
295 rIn |= const_cast<DffPropertyReader&>(*this);
300 const_cast<DffPropertyReader*>(this)->mnFix16Angle = Fix16ToAngle( GetPropertyValue( DFF_Prop_Rotation, 0 ) );
302 #ifdef DBG_CUSTOMSHAPE
304 OUString aURLStr;
306 if( osl::FileBase::getFileURLFromSystemPath( OUString("d:\\ashape.dbg"), aURLStr ) == osl::FileBase::E_None )
308 std::unique_ptr<SvStream> xOut(::utl::UcbStreamHelper::CreateStream( aURLStr, StreamMode::WRITE ));
310 if( xOut )
312 xOut->Seek( STREAM_SEEK_TO_END );
314 if ( IsProperty( DFF_Prop_adjustValue ) || IsProperty( DFF_Prop_pVertices ) )
316 xOut->WriteLine( "" );
317 OString aString("ShapeId: " + OString::number(nShapeId));
318 xOut->WriteLine(aString);
320 for ( sal_uInt32 i = DFF_Prop_adjustValue; i <= DFF_Prop_adjust10Value; i++ )
322 if ( IsProperty( i ) )
324 OString aString("Prop_adjustValue" + OString::number( ( i - DFF_Prop_adjustValue ) + 1 ) +
325 ":" + OString::number(GetPropertyValue(i)) );
326 xOut->WriteLine(aString);
329 sal_Int32 i;
330 for ( i = 320; i < 383; i++ )
332 if ( ( i >= DFF_Prop_adjustValue ) && ( i <= DFF_Prop_adjust10Value ) )
333 continue;
334 if ( IsProperty( i ) )
336 if ( SeekToContent( i, rIn ) )
338 sal_Int32 nLen = (sal_Int32)GetPropertyValue( i );
339 if ( nLen )
341 xOut->WriteLine( "" );
342 OStringBuffer aDesc("Property:" + OString::number(i) +
343 " Size:" + OString::number(nLen));
344 xOut->WriteLine(aDesc.makeStringAndClear());
345 sal_Int16 nNumElem, nNumElemMem, nNumSize;
346 rIn >> nNumElem >> nNumElemMem >> nNumSize;
347 aDesc.append("Entries: " + OString::number(nNumElem) +
348 " Size:" + OString::number(nNumSize));
349 xOut->WriteLine(aDesc.makeStringAndClear());
350 if ( nNumSize < 0 )
351 nNumSize = ( ( -nNumSize ) >> 2 );
352 if ( !nNumSize )
353 nNumSize = 16;
354 nLen -= 6;
355 while ( nLen > 0 )
357 for ( sal_uInt32 j = 0; nLen && ( j < ( nNumSize >> 1 ) ); j++ )
359 for ( sal_uInt32 k = 0; k < 2; k++ )
361 if ( nLen )
363 sal_uInt8 nVal;
364 rIn >> nVal;
365 if ( ( nVal >> 4 ) > 9 )
366 *xOut << (sal_uInt8)( ( nVal >> 4 ) + 'A' - 10 );
367 else
368 *xOut << (sal_uInt8)( ( nVal >> 4 ) + '0' );
370 if ( ( nVal & 0xf ) > 9 )
371 *xOut << (sal_uInt8)( ( nVal & 0xf ) + 'A' - 10 );
372 else
373 *xOut << (sal_uInt8)( ( nVal & 0xf ) + '0' );
375 nLen--;
378 *xOut << (char)( ' ' );
380 xOut->WriteLine( OString() );
384 else
386 OString aString("Property" + OString::number(i) +
387 ":" + OString::number(GetPropertyValue(i)));
388 xOut->WriteLine(aString);
395 #endif
397 rIn.Seek( nFilePos );
401 Degree100 DffPropertyReader::Fix16ToAngle( sal_Int32 nContent )
403 Degree100 nAngle(0);
404 if ( nContent )
406 nAngle = Degree100(( static_cast<sal_Int16>( nContent >> 16) * 100L ) + ( ( ( nContent & 0x0000ffff) * 100L ) >> 16 ));
407 nAngle = NormAngle36000( -nAngle );
409 return nAngle;
412 DffPropertyReader::~DffPropertyReader()
416 static SvStream& operator>>( SvStream& rIn, SvxMSDffConnectorRule& rRule )
418 sal_uInt32 nRuleId;
419 rIn.ReadUInt32( nRuleId )
420 .ReadUInt32( rRule.nShapeA )
421 .ReadUInt32( rRule.nShapeB )
422 .ReadUInt32( rRule.nShapeC )
423 .ReadUInt32( rRule.ncptiA )
424 .ReadUInt32( rRule.ncptiB );
426 return rIn;
429 SvxMSDffSolverContainer::SvxMSDffSolverContainer()
433 SvxMSDffSolverContainer::~SvxMSDffSolverContainer()
437 SvStream& ReadSvxMSDffSolverContainer( SvStream& rIn, SvxMSDffSolverContainer& rContainer )
439 DffRecordHeader aHd;
440 bool bOk = ReadDffRecordHeader( rIn, aHd );
441 if (!bOk || aHd.nRecType != DFF_msofbtSolverContainer)
442 return rIn;
444 DffRecordHeader aCRule;
445 auto nEndPos = DffPropSet::SanitizeEndPos(rIn, aHd.GetRecEndFilePos());
446 while ( rIn.good() && ( rIn.Tell() < nEndPos ) )
448 if (!ReadDffRecordHeader(rIn, aCRule))
449 break;
450 if ( aCRule.nRecType == DFF_msofbtConnectorRule )
452 std::unique_ptr<SvxMSDffConnectorRule> pRule(new SvxMSDffConnectorRule);
453 rIn >> *pRule;
454 rContainer.aCList.push_back( std::move(pRule) );
456 if (!aCRule.SeekToEndOfRecord(rIn))
457 break;
459 return rIn;
462 void SvxMSDffManager::SolveSolver( const SvxMSDffSolverContainer& rSolver )
464 size_t i, nCnt;
465 for ( i = 0, nCnt = rSolver.aCList.size(); i < nCnt; i++ )
467 SvxMSDffConnectorRule* pPtr = rSolver.aCList[ i ].get();
468 if ( pPtr->pCObj )
470 for ( int nN = 0; nN < 2; nN++ )
472 SdrObject* pO;
473 sal_uInt32 nC;
474 ShapeFlag nSpFlags;
475 if ( !nN )
477 pO = pPtr->pAObj;
478 nC = pPtr->ncptiA;
479 nSpFlags = pPtr->nSpFlagsA;
481 else
483 pO = pPtr->pBObj;
484 nC = pPtr->ncptiB;
485 nSpFlags = pPtr->nSpFlagsB;
487 if ( pO )
489 SdrGluePoint aGluePoint;
490 Reference< XShape > aXShape( pO->getUnoShape(), UNO_QUERY );
491 Reference< XShape > aXConnector( pPtr->pCObj->getUnoShape(), UNO_QUERY );
492 SdrGluePointList* pList = pO->ForceGluePointList();
494 sal_Int32 nId = nC;
495 SdrInventor nInventor = pO->GetObjInventor();
497 if( nInventor == SdrInventor::Default )
499 bool bValidGluePoint = false;
500 SdrObjKind nObjId = pO->GetObjIdentifier();
501 switch( nObjId )
503 case SdrObjKind::Group :
504 case SdrObjKind::Graphic :
505 case SdrObjKind::Rectangle :
506 case SdrObjKind::Text :
507 case SdrObjKind::Page :
508 case SdrObjKind::TitleText :
509 case SdrObjKind::OutlineText :
511 if ( nC & 1 )
513 if ( nSpFlags & ShapeFlag::FlipH )
514 nC ^= 2; // 1 <-> 3
516 else
518 if ( nSpFlags & ShapeFlag::FlipV )
519 nC ^= 1; // 0 <-> 2
521 switch( nC )
523 case 0 :
524 nId = 0; // SdrAlign::VERT_TOP;
525 break;
526 case 1 :
527 nId = 3; // SdrAlign::HORZ_RIGHT;
528 break;
529 case 2 :
530 nId = 2; // SdrAlign::VERT_BOTTOM;
531 break;
532 case 3 :
533 nId = 1; // SdrAlign::HORZ_LEFT;
534 break;
536 if ( nId <= 3 )
537 bValidGluePoint = true;
539 break;
540 case SdrObjKind::Polygon :
541 case SdrObjKind::PolyLine :
542 case SdrObjKind::Line :
543 case SdrObjKind::PathLine :
544 case SdrObjKind::PathFill :
545 case SdrObjKind::FreehandLine :
546 case SdrObjKind::FreehandFill :
547 case SdrObjKind::PathPoly :
548 case SdrObjKind::PathPolyLine :
550 if (pList)
552 if (pList->GetCount() > nC )
554 bValidGluePoint = true;
555 nId = static_cast<sal_Int32>((*pList)[ static_cast<sal_uInt16>(nC)].GetId() + 3 );
557 else
559 bool bNotFound = true;
561 tools::PolyPolygon aPolyPoly( EscherPropertyContainer::GetPolyPolygon( aXShape ) );
562 sal_uInt16 k, j, nPolySize = aPolyPoly.Count();
563 if ( nPolySize )
565 tools::Rectangle aBoundRect( aPolyPoly.GetBoundRect() );
566 if ( aBoundRect.GetWidth() && aBoundRect.GetHeight() )
568 sal_uInt32 nPointCount = 0;
569 for ( k = 0; bNotFound && ( k < nPolySize ); k++ )
571 const tools::Polygon& rPolygon = aPolyPoly.GetObject( k );
572 for ( j = 0; bNotFound && ( j < rPolygon.GetSize() ); j++ )
574 PolyFlags eFlags = rPolygon.GetFlags( j );
575 if ( eFlags == PolyFlags::Normal )
577 if ( nC == nPointCount )
579 const Point& rPoint = rPolygon.GetPoint( j );
580 double fXRel = rPoint.X() - aBoundRect.Left();
581 double fYRel = rPoint.Y() - aBoundRect.Top();
582 sal_Int32 nWidth = aBoundRect.GetWidth();
583 if ( !nWidth )
584 nWidth = 1;
585 sal_Int32 nHeight= aBoundRect.GetHeight();
586 if ( !nHeight )
587 nHeight = 1;
588 fXRel /= static_cast<double>(nWidth);
589 fXRel *= 10000;
590 fYRel /= static_cast<double>(nHeight);
591 fYRel *= 10000;
592 aGluePoint.SetPos( Point( static_cast<sal_Int32>(fXRel), static_cast<sal_Int32>(fYRel) ) );
593 aGluePoint.SetPercent( true );
594 aGluePoint.SetAlign( SdrAlign::VERT_TOP | SdrAlign::HORZ_LEFT );
595 aGluePoint.SetEscDir( SdrEscapeDirection::SMART );
596 nId = static_cast<sal_Int32>((*pList)[ pList->Insert( aGluePoint ) ].GetId() + 3 );
597 bNotFound = false;
599 nPointCount++;
605 if ( !bNotFound )
607 bValidGluePoint = true;
612 break;
614 case SdrObjKind::CustomShape :
616 const SfxPoolItem& aCustomShape = static_cast<SdrObjCustomShape*>(pO)->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
617 SdrCustomShapeGeometryItem aGeometryItem( static_cast<const SdrCustomShapeGeometryItem&>(aCustomShape) );
618 static constexpr OUString sPath( u"Path"_ustr );
619 sal_Int16 nGluePointType = EnhancedCustomShapeGluePointType::SEGMENTS;
620 css::uno::Any* pAny = aGeometryItem.GetPropertyValueByName( sPath, u"GluePointType"_ustr );
621 if ( pAny )
622 *pAny >>= nGluePointType;
623 else
625 OUString sShapeType;
626 pAny = aGeometryItem.GetPropertyValueByName( u"Type"_ustr );
627 if ( pAny )
628 *pAny >>= sShapeType;
629 MSO_SPT eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType );
630 nGluePointType = GetCustomShapeConnectionTypeDefault( eSpType );
632 if ( nGluePointType == EnhancedCustomShapeGluePointType::CUSTOM )
634 if ( pList && ( pList->GetCount() > nC ) )
636 bValidGluePoint = true;
637 nId = static_cast<sal_Int32>((*pList)[ static_cast<sal_uInt16>(nC)].GetId() + 3 );
640 else if ( nGluePointType == EnhancedCustomShapeGluePointType::RECT )
642 if ( nC & 1 )
644 if ( nSpFlags & ShapeFlag::FlipH )
645 nC ^= 2; // 1 <-> 3
647 else
649 if ( nSpFlags & ShapeFlag::FlipV )
650 nC ^= 1; // 0 <-> 2
652 switch( nC )
654 case 0 :
655 nId = 0; // SdrAlign::VERT_TOP;
656 break;
657 case 1 :
658 nId = 3; // SdrAlign::HORZ_RIGHT;
659 break;
660 case 2 :
661 nId = 2; // SdrAlign::VERT_BOTTOM;
662 break;
663 case 3 :
664 nId = 1; // SdrAlign::HORZ_LEFT;
665 break;
667 if ( nId <= 3 )
668 bValidGluePoint = true;
670 else if ( nGluePointType == EnhancedCustomShapeGluePointType::SEGMENTS )
672 sal_uInt32 nPt = nC;
673 css::uno::Sequence< css::drawing::EnhancedCustomShapeSegment > aSegments;
674 pAny = aGeometryItem.GetPropertyValueByName( sPath, u"Segments"_ustr );
675 if ( pAny && (*pAny >>= aSegments) )
677 nPt = 0;
678 for ( sal_Int32 k = 1; nC && ( k < aSegments.getLength() ); k++ )
680 sal_Int16 j, nCnt2 = aSegments[ k ].Count;
681 if ( aSegments[ k ].Command != EnhancedCustomShapeSegmentCommand::UNKNOWN )
683 for ( j = 0; nC && ( j < nCnt2 ); j++ )
685 switch( aSegments[ k ].Command )
687 case EnhancedCustomShapeSegmentCommand::ENDSUBPATH :
688 case EnhancedCustomShapeSegmentCommand::CLOSESUBPATH :
689 case EnhancedCustomShapeSegmentCommand::LINETO :
690 case EnhancedCustomShapeSegmentCommand::MOVETO :
692 nC--;
693 nPt++;
695 break;
696 case EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX :
697 case EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY :
698 break;
700 case EnhancedCustomShapeSegmentCommand::CURVETO :
701 case EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO :
702 case EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE :
704 nC--;
705 nPt += 3;
707 break;
708 case EnhancedCustomShapeSegmentCommand::ARCTO :
709 case EnhancedCustomShapeSegmentCommand::ARC :
710 case EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO :
711 case EnhancedCustomShapeSegmentCommand::CLOCKWISEARC :
713 nC--;
714 nPt += 4;
716 break;
722 pAny = aGeometryItem.GetPropertyValueByName( sPath, u"Coordinates"_ustr );
723 if ( pAny )
725 css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aCoordinates;
726 *pAny >>= aCoordinates;
727 if ( nPt < o3tl::make_unsigned(aCoordinates.getLength()) )
729 nId = 4;
730 css::drawing::EnhancedCustomShapeParameterPair& rPara = aCoordinates.getArray()[ nPt ];
731 sal_Int32 nX = 0, nY = 0;
732 if ( ( rPara.First.Value >>= nX ) && ( rPara.Second.Value >>= nY ) )
734 static constexpr OUString sGluePoints( u"GluePoints"_ustr );
735 css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aGluePoints;
736 pAny = aGeometryItem.GetPropertyValueByName( sPath, sGluePoints );
737 if ( pAny )
738 *pAny >>= aGluePoints;
739 sal_Int32 nGluePoints = aGluePoints.getLength();
740 aGluePoints.realloc( nGluePoints + 1 );
741 auto pGluePoints = aGluePoints.getArray();
742 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pGluePoints[ nGluePoints ].First, nX );
743 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pGluePoints[ nGluePoints ].Second, nY );
744 PropertyValue aProp;
745 aProp.Name = sGluePoints;
746 aProp.Value <<= aGluePoints;
747 aGeometryItem.SetPropertyValue( sPath, aProp );
748 bValidGluePoint = true;
749 static_cast<SdrObjCustomShape*>(pO)->SetMergedItem( aGeometryItem );
750 SdrGluePointList* pLst = pO->ForceGluePointList();
751 if ( pLst->GetCount() > nGluePoints )
752 nId = static_cast<sal_Int32>((*pLst)[ static_cast<sal_uInt16>(nGluePoints) ].GetId() + 3 );
758 break;
759 default: ;
761 if ( bValidGluePoint )
763 Reference< XPropertySet > xPropSet( aXConnector, UNO_QUERY );
764 if ( xPropSet.is() )
766 if ( nN )
768 OUString aPropName( u"EndShape"_ustr );
769 SetPropValue( Any(aXShape), xPropSet, aPropName );
770 aPropName = "EndGluePointIndex";
771 SetPropValue( Any(nId), xPropSet, aPropName );
773 else
775 OUString aPropName( u"StartShape"_ustr );
776 SetPropValue( Any(aXShape), xPropSet, aPropName );
777 aPropName = "StartGluePointIndex";
778 SetPropValue( Any(nId), xPropSet, aPropName );
781 // Not sure what this is good for, repaint or broadcast of object change.
782 //( Thus I am adding repaint here
783 pO->SetChanged();
784 pO->BroadcastObjectChange();
794 static basegfx::B2DPolyPolygon GetLineArrow( const sal_Int32 nLineWidth, const sal_uInt32 eLineEnd,
795 const sal_uInt32 eLineWidth, const sal_uInt32 eLineLength,
796 sal_Int32& rnArrowWidth, bool& rbArrowCenter,
797 OUString& rsArrowName, bool bScaleArrow )
799 basegfx::B2DPolyPolygon aRetPolyPoly;
800 // 70 100mm = 2pt = 40 twip. In MS, line width less than 2pt has the same size arrow as 2pt
801 //If the unit is twip. Make all use this unit especially the critical value 70/40.
802 sal_Int32 nLineWidthCritical = bScaleArrow ? 40 : 70;
803 double fLineWidth = nLineWidth < nLineWidthCritical ? nLineWidthCritical : nLineWidth;
805 double fLengthMul, fWidthMul;
806 sal_Int32 nLineNumber;
807 switch( eLineLength )
809 default :
810 case mso_lineMediumLenArrow : fLengthMul = 3.0; nLineNumber = 2; break;
811 case mso_lineShortArrow : fLengthMul = 2.0; nLineNumber = 1; break;
812 case mso_lineLongArrow : fLengthMul = 5.0; nLineNumber = 3; break;
814 switch( eLineWidth )
816 default :
817 case mso_lineMediumWidthArrow : fWidthMul = 3.0; nLineNumber += 3; break;
818 case mso_lineNarrowArrow : fWidthMul = 2.0; break;
819 case mso_lineWideArrow : fWidthMul = 5.0; nLineNumber += 6; break;
822 rbArrowCenter = false;
823 OUStringBuffer aArrowName;
824 switch ( eLineEnd )
826 case mso_lineArrowEnd :
828 basegfx::B2DPolygon aTriangle;
829 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50, 0.0 ));
830 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth, fLengthMul * fLineWidth ));
831 aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth ));
832 aTriangle.setClosed(true);
833 aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle);
834 aArrowName.append("msArrowEnd ");
836 break;
838 case mso_lineArrowOpenEnd :
840 switch( eLineLength )
842 default :
843 case mso_lineMediumLenArrow : fLengthMul = 4.5; break;
844 case mso_lineShortArrow : fLengthMul = 3.5; break;
845 case mso_lineLongArrow : fLengthMul = 6.0; break;
847 switch( eLineWidth )
849 default :
850 case mso_lineMediumWidthArrow : fWidthMul = 4.5; break;
851 case mso_lineNarrowArrow : fWidthMul = 3.5; break;
852 case mso_lineWideArrow : fWidthMul = 6.0; break;
854 basegfx::B2DPolygon aTriangle;
855 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , 0.0 ));
856 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth, fLengthMul * fLineWidth * 0.91 ));
857 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.85, fLengthMul * fLineWidth ));
858 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50, fLengthMul * fLineWidth * 0.36 ));
859 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.15, fLengthMul * fLineWidth ));
860 aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth * 0.91 ));
861 aTriangle.setClosed(true);
862 aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle);
863 aArrowName.append("msArrowOpenEnd ");
865 break;
866 case mso_lineArrowStealthEnd :
868 basegfx::B2DPolygon aTriangle;
869 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , 0.0 ));
870 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth , fLengthMul * fLineWidth ));
871 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , fLengthMul * fLineWidth * 0.60 ));
872 aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth ));
873 aTriangle.setClosed(true);
874 aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle);
875 aArrowName.append("msArrowStealthEnd ");
877 break;
878 case mso_lineArrowDiamondEnd :
880 basegfx::B2DPolygon aTriangle;
881 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , 0.0 ));
882 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth , fLengthMul * fLineWidth * 0.50 ));
883 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , fLengthMul * fLineWidth ));
884 aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth * 0.50 ));
885 aTriangle.setClosed(true);
886 aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle);
887 rbArrowCenter = true;
888 aArrowName.append("msArrowDiamondEnd ");
890 break;
891 case mso_lineArrowOvalEnd :
893 aRetPolyPoly = basegfx::B2DPolyPolygon(
894 XPolygon(
895 Point( static_cast<sal_Int32>( fWidthMul * fLineWidth * 0.50 ), 0 ),
896 static_cast<sal_Int32>( fWidthMul * fLineWidth * 0.50 ),
897 static_cast<sal_Int32>( fLengthMul * fLineWidth * 0.50 ),
898 0_deg100, 36000_deg100 ).getB2DPolygon() );
899 rbArrowCenter = true;
900 aArrowName.append("msArrowOvalEnd ");
902 break;
903 default: break;
905 aArrowName.append(nLineNumber);
906 rsArrowName = aArrowName.makeStringAndClear();
907 rnArrowWidth = static_cast<sal_Int32>( fLineWidth * fWidthMul );
909 return aRetPolyPoly;
912 void DffPropertyReader::ApplyLineAttributes( SfxItemSet& rSet, const MSO_SPT eShapeType ) const // #i28269#
914 sal_uInt32 nLineFlags(GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 ));
916 if(!IsHardAttribute( DFF_Prop_fLine ) && !IsCustomShapeStrokedByDefault( eShapeType ))
918 nLineFlags &= ~0x08;
921 if ( nLineFlags & 8 )
923 // Line Attributes
924 sal_Int32 nLineWidth = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_lineWidth, 9525 ));
926 // support LineCap
927 auto eLineCap = GetPropertyValue(DFF_Prop_lineEndCapStyle, mso_lineEndCapFlat);
929 switch(eLineCap)
931 default: /* case mso_lineEndCapFlat */
933 // no need to set, it is the default. If this changes, this needs to be activated
934 // rSet.Put(XLineCapItem(css::drawing::LineCap_BUTT));
935 break;
937 case mso_lineEndCapRound:
939 rSet.Put(XLineCapItem(css::drawing::LineCap_ROUND));
940 break;
942 case mso_lineEndCapSquare:
944 rSet.Put(XLineCapItem(css::drawing::LineCap_SQUARE));
945 break;
949 auto eLineDashing = GetPropertyValue( DFF_Prop_lineDashing, mso_lineSolid);
950 if (eLineDashing == mso_lineSolid || nLineWidth < 0)
951 rSet.Put(XLineStyleItem( drawing::LineStyle_SOLID ) );
952 else
954 // Despite of naming "dot" and "dash", that are all dashes and a "dot" can be longer
955 // than a "dash". The naming indicates the order, "dot" is always the first dash and
956 // "dash" is always the second dash. MS Office always starts with the longer dash, so
957 // set it here accordingly.
958 // The preset from binary is essentially the same as from OOXML. So here the same
959 // setting is used as in oox import. The comment corresponds to
960 // "dots, dotLen, dashes, dashLen, distance" there.
961 // MS Office uses always relative length, so no need to consider nLineWidth
962 // here. Values are of kind 300 for 300% in css::drawing::DashStyle, for example.
964 sal_uInt16 nDots = 1; // in all cases, "solid" is treated above
965 // initialize, will be changed if necessary
966 sal_uInt32 nDotLen = 300;
967 sal_uInt16 nDashes = 0;
968 sal_uInt32 nDashLen = 0;
969 sal_uInt32 nDistance = 300;
970 switch ( eLineDashing )
972 default:
973 case mso_lineDotSys : // 1 1 0 0 1
975 nDotLen =100;
976 nDistance = 100;
978 break;
980 case mso_lineDashGEL : // 1 4 0 0 3
982 nDotLen = 400;
984 break;
986 case mso_lineDashDotGEL : // 1 4 1 1 3
988 nDotLen = 400;
989 nDashes = 1;
990 nDashLen = 100;
992 break;
994 case mso_lineLongDashGEL : // 1 8 0 0 3
996 nDotLen = 800;
998 break;
1000 case mso_lineLongDashDotGEL : // 1 8 1 1 3
1002 nDotLen = 800;
1003 nDashes = 1;
1004 nDashLen = 100;
1006 break;
1008 case mso_lineLongDashDotDotGEL: // 1 8 2 1 3
1010 nDotLen = 800;
1011 nDashes = 2;
1012 nDashLen = 100;
1014 break;
1016 case mso_lineDotGEL: // 1 1 0 0 3
1018 nDotLen = 100;
1020 break;
1022 case mso_lineDashSys: // 1 3 0 0 1
1024 nDistance = 100;
1026 break;
1028 case mso_lineDashDotSys: // 1 3 1 1 1
1030 nDashes = 1;
1031 nDashLen = 100;
1032 nDistance = 100;
1034 break;
1036 case mso_lineDashDotDotSys: // 1 3 2 1 1
1038 nDashes = 2;
1039 nDashLen = 100;
1040 nDistance = 100;
1042 break;
1044 rSet.Put( XLineDashItem( OUString(), XDash( css::drawing::DashStyle_RECTRELATIVE, nDots, nDotLen, nDashes, nDashLen, nDistance ) ) );
1045 rSet.Put( XLineStyleItem( drawing::LineStyle_DASH ) );
1047 rSet.Put( XLineColorItem( OUString(), rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_lineColor, 0 ) ) ) );
1048 if ( IsProperty( DFF_Prop_lineOpacity ) )
1050 double nTrans = GetPropertyValue(DFF_Prop_lineOpacity, 0x10000);
1051 nTrans = (nTrans * 100) / 65536;
1052 rSet.Put(XLineTransparenceItem(
1053 sal_uInt16(100 - ::rtl::math::round(nTrans))));
1056 rManager.ScaleEmu( nLineWidth );
1057 rSet.Put( XLineWidthItem( nLineWidth ) );
1059 // SJ: LineJoint (setting each time a line is set, because our internal joint type has another default)
1060 MSO_LineJoin eLineJointDefault = mso_lineJoinMiter;
1061 if ( eShapeType == mso_sptMin )
1062 eLineJointDefault = mso_lineJoinRound;
1063 auto eLineJoint = GetPropertyValue(DFF_Prop_lineJoinStyle, eLineJointDefault);
1064 css::drawing::LineJoint eXLineJoint( css::drawing::LineJoint_MITER );
1065 if ( eLineJoint == mso_lineJoinBevel )
1066 eXLineJoint = css::drawing::LineJoint_BEVEL;
1067 else if ( eLineJoint == mso_lineJoinRound )
1068 eXLineJoint = css::drawing::LineJoint_ROUND;
1069 rSet.Put( XLineJointItem( eXLineJoint ) );
1071 if ( nLineFlags & 0x10 )
1073 bool bScaleArrows = rManager.pSdrModel->GetScaleUnit() == MapUnit::MapTwip;
1075 // LineStart
1077 if ( IsProperty( DFF_Prop_lineStartArrowhead ) )
1079 auto eLineEnd = GetPropertyValue(DFF_Prop_lineStartArrowhead, 0);
1080 auto eWidth = GetPropertyValue(DFF_Prop_lineStartArrowWidth, mso_lineMediumWidthArrow);
1081 auto eLength = GetPropertyValue(DFF_Prop_lineStartArrowLength, mso_lineMediumLenArrow);
1083 sal_Int32 nArrowWidth;
1084 bool bArrowCenter;
1085 OUString aArrowName;
1086 basegfx::B2DPolyPolygon aPolyPoly(GetLineArrow( nLineWidth, eLineEnd, eWidth, eLength, nArrowWidth, bArrowCenter, aArrowName, bScaleArrows ));
1088 rSet.Put( XLineStartWidthItem( nArrowWidth ) );
1089 rSet.Put( XLineStartItem( std::move(aArrowName), std::move(aPolyPoly) ) );
1090 rSet.Put( XLineStartCenterItem( bArrowCenter ) );
1093 // LineEnd
1095 if ( IsProperty( DFF_Prop_lineEndArrowhead ) )
1097 auto eLineEnd = GetPropertyValue(DFF_Prop_lineEndArrowhead, 0);
1098 auto eWidth = GetPropertyValue(DFF_Prop_lineEndArrowWidth, mso_lineMediumWidthArrow);
1099 auto eLength = GetPropertyValue(DFF_Prop_lineEndArrowLength, mso_lineMediumLenArrow);
1101 sal_Int32 nArrowWidth;
1102 bool bArrowCenter;
1103 OUString aArrowName;
1104 basegfx::B2DPolyPolygon aPolyPoly(GetLineArrow( nLineWidth, eLineEnd, eWidth, eLength, nArrowWidth, bArrowCenter, aArrowName, bScaleArrows ));
1106 rSet.Put( XLineEndWidthItem( nArrowWidth ) );
1107 rSet.Put( XLineEndItem( std::move(aArrowName), std::move(aPolyPoly) ) );
1108 rSet.Put( XLineEndCenterItem( bArrowCenter ) );
1112 else
1113 rSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
1116 namespace {
1118 struct ShadeColor
1120 Color aColor;
1121 double fDist;
1123 ShadeColor( const Color& rC, double fR ) : aColor( rC ), fDist( fR ) {};
1128 static void GetShadeColors( const SvxMSDffManager& rManager, const DffPropertyReader& rProperties, SvStream& rIn, std::vector< ShadeColor >& rShadeColors )
1130 sal_uInt64 nPos = rIn.Tell();
1131 if ( rProperties.IsProperty( DFF_Prop_fillShadeColors ) )
1133 sal_uInt16 i = 0, nNumElem = 0;
1134 bool bOk = false;
1135 if (rProperties.SeekToContent(DFF_Prop_fillShadeColors, rIn))
1137 sal_uInt16 nNumElemReserved = 0, nSize = 0;
1138 rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemReserved ).ReadUInt16( nSize );
1139 //sanity check that the stream is long enough to fulfill nNumElem * 2 sal_Int32s
1140 bOk = rIn.remainingSize() / (2*sizeof(sal_Int32)) >= nNumElem;
1142 if (bOk)
1144 for ( ; i < nNumElem; i++ )
1146 sal_Int32 nColor(0);
1147 sal_Int32 nDist(0);
1149 rIn.ReadInt32( nColor ).ReadInt32( nDist );
1150 rShadeColors.emplace_back( rManager.MSO_CLR_ToColor( nColor, DFF_Prop_fillColor ), 1.0 - ( nDist / 65536.0 ) );
1154 if ( rShadeColors.empty() )
1156 rShadeColors.emplace_back( rManager.MSO_CLR_ToColor( rProperties.GetPropertyValue( DFF_Prop_fillBackColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillBackColor ), 0 );
1157 rShadeColors.emplace_back( rManager.MSO_CLR_ToColor( rProperties.GetPropertyValue( DFF_Prop_fillColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillColor ), 1 );
1159 rIn.Seek( nPos );
1162 static void ApplyRectangularGradientAsBitmap( const SvxMSDffManager& rManager, SvStream& rIn, SfxItemSet& rSet, const std::vector< ShadeColor >& rShadeColors, const DffObjData& rObjData, Degree100 nFix16Angle )
1164 Size aBitmapSizePixel( static_cast< sal_Int32 >( ( rObjData.aBoundRect.GetWidth() / 2540.0 ) * 90.0 ), // we will create a bitmap with 90 dpi
1165 static_cast< sal_Int32 >( ( rObjData.aBoundRect.GetHeight() / 2540.0 ) * 90.0 ) );
1166 if (aBitmapSizePixel.IsEmpty() || aBitmapSizePixel.Width() > 1024 || aBitmapSizePixel.Height() > 1024)
1167 return;
1169 double fFocusX = rManager.GetPropertyValue( DFF_Prop_fillToRight, 0 ) / 65536.0;
1170 double fFocusY = rManager.GetPropertyValue( DFF_Prop_fillToBottom, 0 ) / 65536.0;
1172 vcl::bitmap::RawBitmap aBitmap(aBitmapSizePixel, 24);
1174 for ( tools::Long nY = 0; nY < aBitmapSizePixel.Height(); nY++ )
1176 for ( tools::Long nX = 0; nX < aBitmapSizePixel.Width(); nX++ )
1178 double fX = static_cast< double >( nX ) / aBitmapSizePixel.Width();
1179 double fY = static_cast< double >( nY ) / aBitmapSizePixel.Height();
1181 double fD, fDist;
1182 if ( fX < fFocusX )
1184 if ( fY < fFocusY )
1186 if ( fX > fY )
1188 fDist = fY;
1189 fD = fFocusY;
1191 else
1193 fDist = fX;
1194 fD = fFocusX;
1197 else
1199 if ( fX > ( 1 - fY ) )
1201 fDist = 1 - fY;
1202 fD = 1 - fFocusY;
1204 else
1206 fDist = fX;
1207 fD = fFocusX;
1211 else
1213 if ( fY < fFocusY )
1215 if ( ( 1 - fX ) > fY )
1217 fDist = fY;
1218 fD = fFocusY;
1220 else
1222 fDist = 1 - fX;
1223 fD = 1 - fFocusX;
1226 else
1228 if ( ( 1 - fX ) > ( 1 - fY ) )
1230 fDist = 1 - fY;
1231 fD = 1 - fFocusY;
1233 else
1235 fDist = 1 - fX;
1236 fD = 1 - fFocusX;
1240 if ( fD != 0.0 )
1241 fDist /= fD;
1243 double fA = 0.0;
1244 Color aColorA = rShadeColors.front().aColor;
1245 double fB = 1.0;
1246 Color aColorB( aColorA );
1247 for ( const auto& rShadeColor : rShadeColors )
1249 if ( fA <= rShadeColor.fDist && rShadeColor.fDist <= fDist )
1251 fA = rShadeColor.fDist;
1252 aColorA = rShadeColor.aColor;
1254 if ( fDist < rShadeColor.fDist && rShadeColor.fDist <= fB )
1256 fB = rShadeColor.fDist;
1257 aColorB = rShadeColor.aColor;
1260 double fRed = aColorA.GetRed(), fGreen = aColorA.GetGreen(), fBlue = aColorA.GetBlue();
1261 double fD1 = fB - fA;
1262 if ( fD1 != 0.0 )
1264 fRed += ( ( ( fDist - fA ) * ( aColorB.GetRed() - aColorA.GetRed() ) ) / fD1 ); // + aQuantErrCurrScan[ nX ].fRed;
1265 fGreen += ( ( ( fDist - fA ) * ( aColorB.GetGreen() - aColorA.GetGreen() ) ) / fD1 ); // + aQuantErrCurrScan[ nX ].fGreen;
1266 fBlue += ( ( ( fDist - fA ) * ( aColorB.GetBlue() - aColorA.GetBlue() ) ) / fD1 ); // + aQuantErrCurrScan[ nX ].fBlue;
1268 sal_Int16 nRed = static_cast< sal_Int16 >( fRed + 0.5 );
1269 sal_Int16 nGreen = static_cast< sal_Int16 >( fGreen + 0.5 );
1270 sal_Int16 nBlue = static_cast< sal_Int16 >( fBlue + 0.5 );
1271 if ( nRed < 0 )
1272 nRed = 0;
1273 if ( nRed > 255 )
1274 nRed = 255;
1275 if ( nGreen < 0 )
1276 nGreen = 0;
1277 if ( nGreen > 255 )
1278 nGreen = 255;
1279 if ( nBlue < 0 )
1280 nBlue = 0;
1281 if ( nBlue > 255 )
1282 nBlue = 255;
1284 aBitmap.SetPixel(nY, nX, Color(static_cast<sal_Int8>(nRed), static_cast<sal_Int8>(nGreen), static_cast<sal_Int8>(nBlue)));
1287 BitmapEx aBitmapEx = vcl::bitmap::CreateFromData( std::move(aBitmap) );
1289 if ( nFix16Angle )
1291 bool bRotateWithShape = true; // sal_True seems to be default
1292 sal_uInt64 nPos = rIn.Tell();
1293 if ( const_cast< SvxMSDffManager& >( rManager ).maShapeRecords.SeekToContent( rIn, DFF_msofbtUDefProp, SEEK_FROM_CURRENT_AND_RESTART ) )
1295 const_cast< SvxMSDffManager& >( rManager ).maShapeRecords.Current()->SeekToBegOfRecord( rIn );
1296 DffPropertyReader aSecPropSet( rManager );
1297 aSecPropSet.ReadPropSet( rIn, nullptr );
1298 sal_Int32 nSecFillProperties = aSecPropSet.GetPropertyValue( DFF_Prop_fNoFillHitTest, 0x200020 );
1299 bRotateWithShape = ( nSecFillProperties & 0x0020 );
1301 rIn.Seek( nPos );
1302 if ( bRotateWithShape )
1304 // convert from 100th to 10th degrees
1305 aBitmapEx.Rotate( to<Degree10>(nFix16Angle), rShadeColors[ 0 ].aColor );
1307 BmpMirrorFlags nMirrorFlags = BmpMirrorFlags::NONE;
1308 if ( rObjData.nSpFlags & ShapeFlag::FlipV )
1309 nMirrorFlags |= BmpMirrorFlags::Vertical;
1310 if ( rObjData.nSpFlags & ShapeFlag::FlipH )
1311 nMirrorFlags |= BmpMirrorFlags::Horizontal;
1312 if ( nMirrorFlags != BmpMirrorFlags::NONE )
1313 aBitmapEx.Mirror( nMirrorFlags );
1317 rSet.Put(XFillBmpTileItem(false));
1318 rSet.Put(XFillBitmapItem(OUString(), Graphic(aBitmapEx)));
1321 void DffPropertyReader::ApplyFillAttributes( SvStream& rIn, SfxItemSet& rSet, const DffObjData& rObjData ) const
1323 sal_uInt32 nFillFlags(GetPropertyValue( DFF_Prop_fNoFillHitTest, 0 ));
1325 std::vector< ShadeColor > aShadeColors;
1326 GetShadeColors( rManager, *this, rIn, aShadeColors );
1328 if(!IsHardAttribute( DFF_Prop_fFilled ) && !IsCustomShapeFilledByDefault( rObjData.eShapeType ))
1330 nFillFlags &= ~0x10;
1333 if ( nFillFlags & 0x10 )
1335 auto eMSO_FillType = GetPropertyValue(DFF_Prop_fillType, mso_fillSolid);
1336 bool bUseSlideBackground = false;
1337 drawing::FillStyle eXFill = drawing::FillStyle_NONE;
1338 switch( eMSO_FillType )
1340 case mso_fillSolid : // Fill with a solid color
1341 eXFill = drawing::FillStyle_SOLID;
1342 break;
1343 case mso_fillPattern : // Fill with a pattern (bitmap)
1344 case mso_fillTexture : // A texture (pattern with its own color map)
1345 case mso_fillPicture : // Center a picture in the shape
1346 eXFill = drawing::FillStyle_BITMAP;
1347 break;
1348 case mso_fillShadeCenter : // Shade from bounding rectangle to end point
1350 //If it is imported as a bitmap, it will not work well with transparency especially 100
1351 //But the gradient look well comparing with imported as gradient. And rotate with shape
1352 //also works better. So here just keep it.
1353 if ( rObjData.aBoundRect.IsEmpty() )// size of object needed to be able
1354 eXFill = drawing::FillStyle_GRADIENT; // to create a bitmap substitution
1355 else
1356 eXFill = drawing::FillStyle_BITMAP;
1358 break;
1359 case mso_fillShade : // Shade from start to end points
1360 case mso_fillShadeShape : // Shade from shape outline to end point
1361 case mso_fillShadeScale : // Similar to mso_fillShade, but the fillAngle
1362 case mso_fillShadeTitle : // special type - shade to title --- for PP
1363 eXFill = drawing::FillStyle_GRADIENT;
1364 break;
1365 case mso_fillBackground : // Use the background fill color/pattern
1366 eXFill = drawing::FillStyle_NONE;
1367 bUseSlideBackground = true;
1368 break;
1369 default: break;
1371 rSet.Put( XFillStyleItem( eXFill ) );
1373 double dTrans = 1.0;
1374 double dBackTrans = 1.0;
1375 if (IsProperty(DFF_Prop_fillOpacity))
1377 dTrans = GetPropertyValue(DFF_Prop_fillOpacity, 0) / 65536.0;
1378 if ( eXFill != drawing::FillStyle_GRADIENT )
1380 dTrans = dTrans * 100;
1381 rSet.Put(XFillTransparenceItem(
1382 sal_uInt16(100 - ::rtl::math::round(dTrans))));
1386 if ( IsProperty(DFF_Prop_fillBackOpacity) )
1387 dBackTrans = GetPropertyValue(DFF_Prop_fillBackOpacity, 0) / 65536.0;
1389 if ( ( eMSO_FillType == mso_fillShadeCenter ) && ( eXFill == drawing::FillStyle_BITMAP ) )
1391 ApplyRectangularGradientAsBitmap( rManager, rIn, rSet, aShadeColors, rObjData, mnFix16Angle );
1393 else if ( eXFill == drawing::FillStyle_GRADIENT )
1395 ImportGradientColor ( rSet, eMSO_FillType, dTrans , dBackTrans );
1397 else if ( eXFill == drawing::FillStyle_BITMAP )
1399 if( IsProperty( DFF_Prop_fillBlip ) )
1401 Graphic aGraf;
1402 // first try to get BLIP from cache
1403 bool bOK = const_cast<SvxMSDffManager&>(rManager).GetBLIP( GetPropertyValue( DFF_Prop_fillBlip, 0 ), aGraf );
1404 // then try directly from stream (i.e. Excel chart hatches/bitmaps)
1405 if ( !bOK )
1406 bOK = SeekToContent( DFF_Prop_fillBlip, rIn ) && SvxMSDffManager::GetBLIPDirect( rIn, aGraf );
1407 if ( bOK )
1409 if ( eMSO_FillType == mso_fillPattern )
1411 Bitmap aBmp( aGraf.GetBitmapEx().GetBitmap() );
1412 if (aBmp.GetSizePixel().Width() == 8 &&
1413 aBmp.GetSizePixel().Height() == 8 &&
1414 aBmp.getPixelFormat() == vcl::PixelFormat::N8_BPP)
1416 Color aCol1( COL_WHITE ), aCol2( COL_WHITE );
1418 if ( IsProperty( DFF_Prop_fillColor ) )
1419 aCol1 = rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillColor, 0 ), DFF_Prop_fillColor );
1421 if ( IsProperty( DFF_Prop_fillBackColor ) )
1422 aCol2 = rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillBackColor, 0 ), DFF_Prop_fillBackColor );
1424 // Create a bitmap for the pattern with expected colors
1425 vcl::bitmap::RawBitmap aResult(Size(8, 8), 24);
1427 BitmapScopedReadAccess pRead(aBmp);
1429 for (tools::Long y = 0; y < aResult.Height(); ++y)
1431 Scanline pScanlineRead = pRead->GetScanline( y );
1432 for (tools::Long x = 0; x < aResult.Width(); ++x)
1434 Color aReadColor;
1435 if (pRead->HasPalette())
1436 aReadColor = pRead->GetPaletteColor(pRead->GetIndexFromData(pScanlineRead, x));
1437 else
1438 aReadColor = pRead->GetPixelFromData(pScanlineRead, x);
1440 if (aReadColor == Color(0))
1441 aResult.SetPixel(y, x, aCol2);
1442 else
1443 aResult.SetPixel(y, x, aCol1);
1447 aGraf = Graphic(vcl::bitmap::CreateFromData(std::move(aResult)));
1450 rSet.Put(XFillBitmapItem(OUString(), std::move(aGraf)));
1452 else if ( eMSO_FillType == mso_fillTexture )
1454 rSet.Put(XFillBmpTileItem(true));
1455 rSet.Put(XFillBitmapItem(OUString(), std::move(aGraf)));
1456 rSet.Put(XFillBmpSizeXItem(GetPropertyValue(DFF_Prop_fillWidth, 0) / 360));
1457 rSet.Put(XFillBmpSizeYItem(GetPropertyValue(DFF_Prop_fillHeight, 0) / 360));
1458 rSet.Put(XFillBmpSizeLogItem(true));
1460 else
1462 rSet.Put(XFillBitmapItem(OUString(), std::move(aGraf)));
1463 rSet.Put(XFillBmpTileItem(false));
1468 else if (eXFill == drawing::FillStyle_NONE && bUseSlideBackground)
1470 rSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
1471 XFillUseSlideBackgroundItem aFillBgItem(true);
1472 rSet.Put(aFillBgItem);
1475 else
1476 rSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
1479 void DffPropertyReader::ApplyCustomShapeTextAttributes( SfxItemSet& rSet ) const
1481 bool bVerticalText = false;
1482 sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 25 * 3600 ) / 360; // 0.25 cm (emu)
1483 sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 25 * 3600 ) / 360; // 0.25 cm (emu)
1484 sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 13 * 3600 ) / 360; // 0.13 cm (emu)
1485 sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 13 * 3600 ) /360; // 0.13 cm (emu)
1487 SdrTextVertAdjust eTVA;
1488 SdrTextHorzAdjust eTHA;
1490 if ( IsProperty( DFF_Prop_txflTextFlow ) )
1492 auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF;
1493 switch( eTextFlow )
1495 case mso_txflTtoBA : /* #68110# */ // Top to Bottom @-font, oben -> unten
1496 case mso_txflTtoBN : // Top to Bottom non-@, oben -> unten
1497 case mso_txflVertN : // Vertical, non-@, oben -> unten
1498 bVerticalText = true; // nTextRotationAngle += 27000;
1499 break;
1500 default: break;
1503 sal_Int32 nFontDirection = GetPropertyValue( DFF_Prop_cdirFont, mso_cdir0 );
1504 if ( ( nFontDirection == 1 ) || ( nFontDirection == 3 ) )
1505 bVerticalText = !bVerticalText;
1507 if ( bVerticalText )
1509 eTHA = SDRTEXTHORZADJUST_CENTER;
1511 // read text anchor
1512 sal_uInt32 eTextAnchor = GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop );
1514 switch( eTextAnchor )
1516 case mso_anchorTop:
1517 case mso_anchorTopCentered:
1518 case mso_anchorTopBaseline:
1519 case mso_anchorTopCenteredBaseline:
1520 eTHA = SDRTEXTHORZADJUST_RIGHT;
1521 break;
1523 case mso_anchorMiddle :
1524 case mso_anchorMiddleCentered:
1525 eTHA = SDRTEXTHORZADJUST_CENTER;
1526 break;
1528 case mso_anchorBottom:
1529 case mso_anchorBottomCentered:
1530 case mso_anchorBottomBaseline:
1531 case mso_anchorBottomCenteredBaseline:
1532 eTHA = SDRTEXTHORZADJUST_LEFT;
1533 break;
1535 // if there is a 100% use of following attributes, the textbox can been aligned also in vertical direction
1536 switch ( eTextAnchor )
1538 case mso_anchorTopCentered :
1539 case mso_anchorMiddleCentered :
1540 case mso_anchorBottomCentered :
1541 case mso_anchorTopCenteredBaseline:
1542 case mso_anchorBottomCenteredBaseline:
1543 eTVA = SDRTEXTVERTADJUST_CENTER;
1544 break;
1546 default :
1547 eTVA = SDRTEXTVERTADJUST_TOP;
1548 break;
1551 else
1553 eTVA = SDRTEXTVERTADJUST_CENTER;
1555 // read text anchor
1556 sal_uInt32 eTextAnchor = GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop );
1558 switch( eTextAnchor )
1560 case mso_anchorTop:
1561 case mso_anchorTopCentered:
1562 case mso_anchorTopBaseline:
1563 case mso_anchorTopCenteredBaseline:
1564 eTVA = SDRTEXTVERTADJUST_TOP;
1565 break;
1567 case mso_anchorMiddle :
1568 case mso_anchorMiddleCentered:
1569 eTVA = SDRTEXTVERTADJUST_CENTER;
1570 break;
1572 case mso_anchorBottom:
1573 case mso_anchorBottomCentered:
1574 case mso_anchorBottomBaseline:
1575 case mso_anchorBottomCenteredBaseline:
1576 eTVA = SDRTEXTVERTADJUST_BOTTOM;
1577 break;
1579 // if there is a 100% usage of following attributes, the textbox can be aligned also in horizontal direction
1580 switch ( eTextAnchor )
1582 case mso_anchorTopCentered :
1583 case mso_anchorMiddleCentered :
1584 case mso_anchorBottomCentered :
1585 case mso_anchorTopCenteredBaseline:
1586 case mso_anchorBottomCenteredBaseline:
1587 eTHA = SDRTEXTHORZADJUST_CENTER; // the text has to be displayed using the full width;
1588 break;
1590 default :
1591 eTHA = SDRTEXTHORZADJUST_LEFT;
1592 break;
1595 rSet.Put( SvxFrameDirectionItem( bVerticalText ? SvxFrameDirection::Vertical_RL_TB : SvxFrameDirection::Horizontal_LR_TB, EE_PARA_WRITINGDIR ) );
1597 rSet.Put( SdrTextVertAdjustItem( eTVA ) );
1598 rSet.Put( SdrTextHorzAdjustItem( eTHA ) );
1600 rSet.Put( makeSdrTextLeftDistItem( nTextLeft ) );
1601 rSet.Put( makeSdrTextRightDistItem( nTextRight ) );
1602 rSet.Put( makeSdrTextUpperDistItem( nTextTop ) );
1603 rSet.Put( makeSdrTextLowerDistItem( nTextBottom ) );
1605 rSet.Put( makeSdrTextWordWrapItem( GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare) != mso_wrapNone ) );
1606 rSet.Put( makeSdrTextAutoGrowHeightItem( ( GetPropertyValue( DFF_Prop_FitTextToShape, 0 ) & 2 ) != 0 ) );
1609 void DffPropertyReader::ApplyCustomShapeGeometryAttributes( SvStream& rIn, SfxItemSet& rSet, const DffObjData& rObjData ) const
1612 sal_uInt32 nAdjustmentsWhichNeedsToBeConverted = 0;
1615 // creating SdrCustomShapeGeometryItem
1617 typedef std::vector< beans::PropertyValue > PropVec;
1619 // aPropVec will be filled with all PropertyValues
1620 PropVec aPropVec;
1621 PropertyValue aProp;
1624 // "Type" property, including the predefined CustomShape type name
1626 aProp.Name = "Type";
1627 aProp.Value <<= EnhancedCustomShapeTypeNames::Get( rObjData.eShapeType );
1628 aPropVec.push_back( aProp );
1631 // "ViewBox"
1634 sal_Int32 nCoordWidth = 21600; // needed to replace handle type center with absolute value
1635 sal_Int32 nCoordHeight= 21600;
1636 if ( IsProperty( DFF_Prop_geoLeft ) || IsProperty( DFF_Prop_geoTop ) || IsProperty( DFF_Prop_geoRight ) || IsProperty( DFF_Prop_geoBottom ) )
1638 css::awt::Rectangle aViewBox;
1639 aViewBox.X = GetPropertyValue( DFF_Prop_geoLeft, 0 );
1640 aViewBox.Y = GetPropertyValue( DFF_Prop_geoTop, 0 );
1641 aViewBox.Width = nCoordWidth = o3tl::saturating_sub<sal_Int32>(GetPropertyValue(DFF_Prop_geoRight, 21600), aViewBox.X);
1642 aViewBox.Height = nCoordHeight = o3tl::saturating_sub<sal_Int32>(GetPropertyValue(DFF_Prop_geoBottom, 21600), aViewBox.Y);
1643 aProp.Name = "ViewBox";
1644 aProp.Value <<= aViewBox;
1645 aPropVec.push_back( aProp );
1648 // TextRotateAngle
1650 if ( IsProperty( DFF_Prop_txflTextFlow ) || IsProperty( DFF_Prop_cdirFont ) )
1652 sal_Int32 nTextRotateAngle = 0;
1653 auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF;
1655 if ( eTextFlow == mso_txflBtoT ) // Bottom to Top non-@
1656 nTextRotateAngle += 90;
1657 switch( GetPropertyValue( DFF_Prop_cdirFont, mso_cdir0 ) ) // SJ: mso_cdir90 and mso_cdir270 will be simulated by
1658 { // activating vertical writing for the text objects
1659 case mso_cdir90 :
1661 if ( eTextFlow == mso_txflTtoBA )
1662 nTextRotateAngle -= 180;
1664 break;
1665 case mso_cdir180: nTextRotateAngle -= 180; break;
1666 case mso_cdir270:
1668 if ( eTextFlow != mso_txflTtoBA )
1669 nTextRotateAngle -= 180;
1671 break;
1672 default: break;
1674 if ( nTextRotateAngle )
1676 double fTextRotateAngle = nTextRotateAngle;
1677 aProp.Name = "TextRotateAngle";
1678 aProp.Value <<= fTextRotateAngle;
1679 aPropVec.push_back( aProp );
1683 // "Extrusion" PropertySequence element
1685 bool bExtrusionOn = ( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 8 ) != 0;
1686 if ( bExtrusionOn )
1688 PropVec aExtrusionPropVec;
1690 // "Extrusion"
1691 aProp.Name = "Extrusion";
1692 aProp.Value <<= bExtrusionOn;
1693 aExtrusionPropVec.push_back( aProp );
1695 // "Brightness"
1696 // MS Office default 0x00004E20 16.16 FixedPoint, 20000/65536=0.30517, ODF default 33%.
1697 // Thus must set value even if default.
1698 double fBrightness = 20000.0;
1699 if ( IsProperty( DFF_Prop_c3DAmbientIntensity ) )
1701 // Value must be in range 0.0 to 1.0 in MS Office binary specification, but larger
1702 // values are in fact interpreted.
1703 fBrightness = GetPropertyValue( DFF_Prop_c3DAmbientIntensity, 0 );
1705 fBrightness /= 655.36;
1706 aProp.Name = "Brightness";
1707 aProp.Value <<= fBrightness;
1708 aExtrusionPropVec.push_back( aProp );
1710 // "Depth" in 1/100mm
1711 if ( IsProperty( DFF_Prop_c3DExtrudeBackward ) || IsProperty( DFF_Prop_c3DExtrudeForward ) )
1713 double fBackDepth = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DExtrudeBackward, 1270 * 360 ))) / 360.0;
1714 double fForeDepth = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DExtrudeForward, 0 ))) / 360.0;
1715 double fDepth = fBackDepth + fForeDepth;
1716 double fFraction = fDepth != 0.0 ? fForeDepth / fDepth : 0;
1717 EnhancedCustomShapeParameterPair aDepthParaPair;
1718 aDepthParaPair.First.Value <<= fDepth;
1719 aDepthParaPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
1720 aDepthParaPair.Second.Value <<= fFraction;
1721 aDepthParaPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
1722 aProp.Name = "Depth";
1723 aProp.Value <<= aDepthParaPair;
1724 aExtrusionPropVec.push_back( aProp );
1726 // "Diffusion"
1727 // ODF default is 0%, MS Office default is 100%. Thus must set value even if default.
1728 double fDiffusion = 100;
1729 if ( IsProperty( DFF_Prop_c3DDiffuseAmt ) )
1731 fDiffusion = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DDiffuseAmt, 0 ));
1732 fDiffusion /= 655.36;
1734 aProp.Name = "Diffusion";
1735 aProp.Value <<= fDiffusion;
1736 aExtrusionPropVec.push_back( aProp );
1738 // "NumberOfLineSegments"
1739 if ( IsProperty( DFF_Prop_c3DTolerance ) )
1741 aProp.Name = "NumberOfLineSegments";
1742 aProp.Value <<= static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DTolerance, 0 ));
1743 aExtrusionPropVec.push_back( aProp );
1745 // "LightFace"
1746 bool bExtrusionLightFace = ( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 1 ) != 0;
1747 aProp.Name = "LightFace";
1748 aProp.Value <<= bExtrusionLightFace;
1749 aExtrusionPropVec.push_back( aProp );
1750 // "FirstLightHarsh"
1751 bool bExtrusionFirstLightHarsh = ( GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 2 ) != 0;
1752 aProp.Name = "FirstLightHarsh";
1753 aProp.Value <<= bExtrusionFirstLightHarsh;
1754 aExtrusionPropVec.push_back( aProp );
1755 // "SecondLightHarsh"
1756 bool bExtrusionSecondLightHarsh = ( GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 1 ) != 0;
1757 aProp.Name = "SecondLightHarsh";
1758 aProp.Value <<= bExtrusionSecondLightHarsh;
1759 aExtrusionPropVec.push_back( aProp );
1761 // "FirstLightLevel"
1762 // MS Office default 0x00009470 16.16 FixedPoint, 38000/65536 = 0.5798, ODF default 66%.
1763 // Thus must set value even if default.
1764 double fFirstLightLevel = 38000.0;
1765 if ( IsProperty( DFF_Prop_c3DKeyIntensity ) )
1767 // value<0 and value>1 are allowed in MS Office. Clamp such in ODF export, not here.
1768 fFirstLightLevel = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DKeyIntensity, 0 ));
1770 fFirstLightLevel /= 655.36;
1771 aProp.Name = "FirstLightLevel";
1772 aProp.Value <<= fFirstLightLevel;
1773 aExtrusionPropVec.push_back( aProp );
1775 // "SecondLightLevel"
1776 // MS Office default 0x00009470 16.16 FixedPoint, 38000/65536 = 0.5798, ODF default 66%.
1777 // Thus must set value even if default.
1778 double fSecondLightLevel = 38000.0;
1779 if ( IsProperty( DFF_Prop_c3DFillIntensity ) )
1781 // value<0 and value>1 are allowed in MS Office. Clamp such in ODF export, not here.
1782 fSecondLightLevel = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DFillIntensity, 0 ));
1784 fSecondLightLevel /= 655.36;
1785 aProp.Name = "SecondLightLevel";
1786 aProp.Value <<= fSecondLightLevel;
1787 aExtrusionPropVec.push_back( aProp );
1789 // "FirstLightDirection"
1790 if ( IsProperty( DFF_Prop_c3DKeyX ) || IsProperty( DFF_Prop_c3DKeyY ) || IsProperty( DFF_Prop_c3DKeyZ ) )
1792 double fLightX = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DKeyX, 50000 )));
1793 double fLightY = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DKeyY, 0 )));
1794 double fLightZ = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DKeyZ, 10000 )));
1795 css::drawing::Direction3D aExtrusionFirstLightDirection( fLightX, fLightY, fLightZ );
1796 aProp.Name = "FirstLightDirection";
1797 aProp.Value <<= aExtrusionFirstLightDirection;
1798 aExtrusionPropVec.push_back( aProp );
1800 // "SecondLightDirection"
1801 if ( IsProperty( DFF_Prop_c3DFillX ) || IsProperty( DFF_Prop_c3DFillY ) || IsProperty( DFF_Prop_c3DFillZ ) )
1803 double fLight2X = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DFillX, sal_uInt32(-50000) )));
1804 double fLight2Y = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DFillY, 0 )));
1805 double fLight2Z = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DFillZ, 10000 )));
1806 css::drawing::Direction3D aExtrusionSecondLightDirection( fLight2X, fLight2Y, fLight2Z );
1807 aProp.Name = "SecondLightDirection";
1808 aProp.Value <<= aExtrusionSecondLightDirection;
1809 aExtrusionPropVec.push_back( aProp );
1812 // "Metal"
1813 bool bExtrusionMetal = ( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 4 ) != 0;
1814 aProp.Name = "Metal";
1815 aProp.Value <<= bExtrusionMetal;
1816 aExtrusionPropVec.push_back( aProp );
1817 aProp.Name = "MetalType";
1818 aProp.Value <<= css::drawing::EnhancedCustomShapeMetalType::MetalMSCompatible;
1819 aExtrusionPropVec.push_back(aProp);
1821 // "ShadeMode"
1822 if ( IsProperty( DFF_Prop_c3DRenderMode ) )
1824 sal_uInt32 nExtrusionRenderMode = GetPropertyValue( DFF_Prop_c3DRenderMode, 0 );
1825 css::drawing::ShadeMode eExtrusionShadeMode( css::drawing::ShadeMode_FLAT );
1826 if ( nExtrusionRenderMode == mso_Wireframe )
1827 eExtrusionShadeMode = css::drawing::ShadeMode_DRAFT;
1829 aProp.Name = "ShadeMode";
1830 aProp.Value <<= eExtrusionShadeMode;
1831 aExtrusionPropVec.push_back( aProp );
1833 // "RotateAngle" in Degree
1834 if ( IsProperty( DFF_Prop_c3DXRotationAngle ) || IsProperty( DFF_Prop_c3DYRotationAngle ) )
1836 double fAngleX = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DXRotationAngle, 0 ))) / 65536.0;
1837 double fAngleY = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DYRotationAngle, 0 ))) / 65536.0;
1838 EnhancedCustomShapeParameterPair aRotateAnglePair;
1839 aRotateAnglePair.First.Value <<= fAngleX;
1840 aRotateAnglePair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
1841 aRotateAnglePair.Second.Value <<= fAngleY;
1842 aRotateAnglePair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
1843 aProp.Name = "RotateAngle";
1844 aProp.Value <<= aRotateAnglePair;
1845 aExtrusionPropVec.push_back( aProp );
1848 // "AutoRotationCenter"
1849 if ( ( GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 8 ) == 0 )
1851 // "RotationCenter"
1852 if ( IsProperty( DFF_Prop_c3DRotationCenterX ) || IsProperty( DFF_Prop_c3DRotationCenterY ) || IsProperty( DFF_Prop_c3DRotationCenterZ ) )
1854 // tdf#145904 X- and Y-component is fraction, Z-component in EMU
1855 css::drawing::Direction3D aRotationCenter(
1856 static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DRotationCenterX, 0 ))) / 65536.0,
1857 static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DRotationCenterY, 0 ))) / 65536.0,
1858 static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DRotationCenterZ, 0 ))) / 360.0 );
1860 aProp.Name = "RotationCenter";
1861 aProp.Value <<= aRotationCenter;
1862 aExtrusionPropVec.push_back( aProp );
1865 // "Shininess"
1866 // MS Office default 5, ODF default 50%.
1867 if ( IsProperty( DFF_Prop_c3DShininess ) )
1869 double fShininess = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DShininess, 0 ));
1870 fShininess *= 10.0; // error in [MS ODRAW] (2021), type is not FixedPoint but long.
1871 aProp.Name = "Shininess";
1872 aProp.Value <<= fShininess;
1873 aExtrusionPropVec.push_back( aProp );
1876 // "Skew"
1877 // MS Office angle file value is 16.16 FixedPoint, default 0xFF790000,
1878 // -8847360/65536=-135, ODF default 45. Thus must set value even if default.
1879 double fSkewAngle = -135.0;
1880 // MS Office amount file value is signed integer in range 0xFFFFFF9C to 0x00000064,
1881 // default 0x00000032, ODF default 50.0
1882 double fSkewAmount = 50.0;
1883 if ( IsProperty( DFF_Prop_c3DSkewAmount ) || IsProperty( DFF_Prop_c3DSkewAngle ) )
1885 fSkewAmount = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DSkewAmount, 50 ));
1886 fSkewAngle = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DSkewAngle, sal::static_int_cast< sal_uInt32 >(-135 * 65536) ));
1887 fSkewAngle /= 65536.0;
1889 EnhancedCustomShapeParameterPair aSkewPair;
1890 aSkewPair.First.Value <<= fSkewAmount;
1891 aSkewPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
1892 aSkewPair.Second.Value <<= fSkewAngle;
1893 aSkewPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
1894 aProp.Name = "Skew";
1895 aProp.Value <<= aSkewPair;
1896 aExtrusionPropVec.push_back( aProp );
1898 // "Specularity"
1899 // Type Fixed point 16.16, percent in API
1900 if ( IsProperty( DFF_Prop_c3DSpecularAmt ) )
1902 double fSpecularity = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DSpecularAmt, 0 ));
1903 fSpecularity /= 655.36;
1904 aProp.Name = "Specularity";
1905 aProp.Value <<= fSpecularity;
1906 aExtrusionPropVec.push_back( aProp );
1908 // "ProjectionMode"
1909 ProjectionMode eProjectionMode = (GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 4) ? ProjectionMode_PARALLEL : ProjectionMode_PERSPECTIVE;
1910 aProp.Name = "ProjectionMode";
1911 aProp.Value <<= eProjectionMode;
1912 aExtrusionPropVec.push_back( aProp );
1914 // "ViewPoint" in 1/100mm
1915 // MS Office default 1250000 EMU=3472.222 Hmm, ODF default 3.5cm
1916 // Thus must set value even if default.
1917 double fViewX = 1250000.0 / 360.0;
1918 double fViewY = -1250000.0 / 360.0;;
1919 double fViewZ = 9000000.0 / 360.0;
1920 if ( IsProperty( DFF_Prop_c3DXViewpoint ) || IsProperty( DFF_Prop_c3DYViewpoint ) || IsProperty( DFF_Prop_c3DZViewpoint ) )
1922 fViewX = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DXViewpoint, 1250000 ))) / 360.0;
1923 fViewY = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DYViewpoint, sal_uInt32(-1250000) )))/ 360.0;
1924 fViewZ = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DZViewpoint, 9000000 ))) / 360.0;
1926 css::drawing::Position3D aExtrusionViewPoint( fViewX, fViewY, fViewZ );
1927 aProp.Name = "ViewPoint";
1928 aProp.Value <<= aExtrusionViewPoint;
1929 aExtrusionPropVec.push_back( aProp );
1931 // "Origin"
1932 if ( IsProperty( DFF_Prop_c3DOriginX ) || IsProperty( DFF_Prop_c3DOriginY ) )
1934 double fOriginX = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DOriginX, 32768 )));
1935 double fOriginY = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DOriginY, sal_uInt32(-32768) )));
1936 fOriginX /= 65536;
1937 fOriginY /= 65536;
1938 EnhancedCustomShapeParameterPair aOriginPair;
1939 aOriginPair.First.Value <<= fOriginX;
1940 aOriginPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
1941 aOriginPair.Second.Value <<= fOriginY;
1942 aOriginPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
1943 aProp.Name = "Origin";
1944 aProp.Value <<= aOriginPair;
1945 aExtrusionPropVec.push_back( aProp );
1947 // "ExtrusionColor"
1948 bool bExtrusionColor = IsProperty( DFF_Prop_c3DExtrusionColor ); // ( GetPropertyValue( DFF_Prop_fc3DLightFace ) & 2 ) != 0;
1949 aProp.Name = "Color";
1950 aProp.Value <<= bExtrusionColor;
1951 aExtrusionPropVec.push_back( aProp );
1952 if ( IsProperty( DFF_Prop_c3DExtrusionColor ) )
1953 rSet.Put( XSecondaryFillColorItem( OUString(), rManager.MSO_CLR_ToColor(
1954 GetPropertyValue( DFF_Prop_c3DExtrusionColor, 0 ), DFF_Prop_c3DExtrusionColor ) ) );
1955 // pushing the whole Extrusion element
1956 aProp.Name = "Extrusion";
1957 aProp.Value <<= comphelper::containerToSequence(aExtrusionPropVec);
1958 aPropVec.push_back( aProp );
1962 // "Equations" PropertySequence element
1964 if ( IsProperty( DFF_Prop_pFormulas ) )
1966 sal_uInt16 nNumElem = 0;
1968 if ( SeekToContent( DFF_Prop_pFormulas, rIn ) )
1970 sal_uInt16 nNumElemMem = 0;
1971 sal_uInt16 nElemSize = 8;
1972 rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemMem ).ReadUInt16( nElemSize );
1974 if ( nNumElem <= 128 )
1976 uno::Sequence< OUString > aEquations( nNumElem );
1977 for ( auto& rEquation : asNonConstRange(aEquations) )
1979 sal_Int16 nP1(0), nP2(0), nP3(0);
1980 sal_uInt16 nFlags(0);
1981 rIn.ReadUInt16( nFlags ).ReadInt16( nP1 ).ReadInt16( nP2 ).ReadInt16( nP3 );
1982 rEquation = EnhancedCustomShape2d::GetEquation( nFlags, nP1, nP2, nP3 );
1984 // pushing the whole Equations element
1985 aProp.Name = "Equations";
1986 aProp.Value <<= aEquations;
1987 aPropVec.push_back( aProp );
1992 // "Handles" PropertySequence element
1994 if ( IsProperty( DFF_Prop_Handles ) )
1996 sal_uInt16 nNumElem = 0;
1997 sal_uInt16 nElemSize = 36;
1999 if ( SeekToContent( DFF_Prop_Handles, rIn ) )
2001 sal_uInt16 nNumElemMem = 0;
2002 rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemMem ).ReadUInt16( nElemSize );
2004 bool bImport = false;
2005 if (nElemSize == 36)
2007 //sanity check that the stream is long enough to fulfill nNumElem * nElemSize;
2008 bImport = rIn.remainingSize() / nElemSize >= nNumElem;
2010 if (bImport)
2012 uno::Sequence< beans::PropertyValues > aHandles( nNumElem );
2013 auto aHandlesRange = asNonConstRange(aHandles);
2014 for (sal_uInt32 i = 0; i < nNumElem; ++i)
2016 PropVec aHandlePropVec;
2017 sal_uInt32 nFlagsTmp(0);
2018 sal_Int32 nPositionX(0), nPositionY(0), nCenterX(0), nCenterY(0), nRangeXMin(0), nRangeXMax(0), nRangeYMin(0), nRangeYMax(0);
2019 rIn.ReadUInt32( nFlagsTmp )
2020 .ReadInt32( nPositionX )
2021 .ReadInt32( nPositionY )
2022 .ReadInt32( nCenterX )
2023 .ReadInt32( nCenterY )
2024 .ReadInt32( nRangeXMin )
2025 .ReadInt32( nRangeXMax )
2026 .ReadInt32( nRangeYMin )
2027 .ReadInt32( nRangeYMax );
2028 SvxMSDffHandleFlags nFlags = static_cast<SvxMSDffHandleFlags>(nFlagsTmp);
2029 if ( nPositionX == 2 ) // replacing center position with absolute value
2030 nPositionX = nCoordWidth / 2;
2031 if ( nPositionY == 2 )
2032 nPositionY = nCoordHeight / 2;
2033 EnhancedCustomShapeParameterPair aPosition;
2034 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.First, nPositionX, true, true );
2035 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.Second, nPositionY, true, false );
2036 aProp.Name = "Position";
2037 aProp.Value <<= aPosition;
2038 aHandlePropVec.push_back( aProp );
2040 if ( nFlags & SvxMSDffHandleFlags::MIRRORED_X )
2042 aProp.Name = "MirroredX";
2043 aProp.Value <<= true;
2044 aHandlePropVec.push_back( aProp );
2046 if ( nFlags & SvxMSDffHandleFlags::MIRRORED_Y )
2048 aProp.Name = "MirroredY";
2049 aProp.Value <<= true;
2050 aHandlePropVec.push_back( aProp );
2052 if ( nFlags & SvxMSDffHandleFlags::SWITCHED )
2054 aProp.Name = "Switched";
2055 aProp.Value <<= true;
2056 aHandlePropVec.push_back( aProp );
2058 if ( nFlags & SvxMSDffHandleFlags::POLAR )
2060 if ( nCenterX == 2 )
2061 nCenterX = nCoordWidth / 2;
2062 if ( nCenterY == 2 )
2063 nCenterY = nCoordHeight / 2;
2064 if ((nPositionY >= 0x256 || nPositionY <= 0x107) && i < sizeof(sal_uInt32) * 8) // position y
2065 nAdjustmentsWhichNeedsToBeConverted |= ( 1U << i );
2066 EnhancedCustomShapeParameterPair aPolar;
2067 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPolar.First, nCenterX, bool( nFlags & SvxMSDffHandleFlags::CENTER_X_IS_SPECIAL ), true );
2068 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPolar.Second, nCenterY, bool( nFlags & SvxMSDffHandleFlags::CENTER_Y_IS_SPECIAL ), false );
2069 aProp.Name = "Polar";
2070 aProp.Value <<= aPolar;
2071 aHandlePropVec.push_back( aProp );
2073 if ( nFlags & SvxMSDffHandleFlags::MAP )
2075 if ( nCenterX == 2 )
2076 nCenterX = nCoordWidth / 2;
2077 if ( nCenterY == 2 )
2078 nCenterY = nCoordHeight / 2;
2079 EnhancedCustomShapeParameterPair aMap;
2080 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aMap.First, nCenterX, bool( nFlags & SvxMSDffHandleFlags::CENTER_X_IS_SPECIAL ), true );
2081 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aMap.Second, nCenterY, bool( nFlags & SvxMSDffHandleFlags::CENTER_Y_IS_SPECIAL ), false );
2082 aProp.Name = "Map";
2083 aProp.Value <<= aMap;
2084 aHandlePropVec.push_back( aProp );
2086 if ( nFlags & SvxMSDffHandleFlags::RANGE )
2088 if ( static_cast<sal_uInt32>(nRangeXMin) != 0x80000000 )
2090 if ( nRangeXMin == 2 )
2091 nRangeXMin = nCoordWidth / 2;
2092 EnhancedCustomShapeParameter aRangeXMinimum;
2093 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMinimum, nRangeXMin,
2094 bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL ), true );
2095 aProp.Name = "RangeXMinimum";
2096 aProp.Value <<= aRangeXMinimum;
2097 aHandlePropVec.push_back( aProp );
2099 if ( static_cast<sal_uInt32>(nRangeXMax) != 0x7fffffff )
2101 if ( nRangeXMax == 2 )
2102 nRangeXMax = nCoordWidth / 2;
2103 EnhancedCustomShapeParameter aRangeXMaximum;
2104 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMaximum, nRangeXMax,
2105 bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL ), false );
2106 aProp.Name = "RangeXMaximum";
2107 aProp.Value <<= aRangeXMaximum;
2108 aHandlePropVec.push_back( aProp );
2110 if ( static_cast<sal_uInt32>(nRangeYMin) != 0x80000000 )
2112 if ( nRangeYMin == 2 )
2113 nRangeYMin = nCoordHeight / 2;
2114 EnhancedCustomShapeParameter aRangeYMinimum;
2115 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMinimum, nRangeYMin,
2116 bool( nFlags & SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL ), true );
2117 aProp.Name = "RangeYMinimum";
2118 aProp.Value <<= aRangeYMinimum;
2119 aHandlePropVec.push_back( aProp );
2121 if ( static_cast<sal_uInt32>(nRangeYMax) != 0x7fffffff )
2123 if ( nRangeYMax == 2 )
2124 nRangeYMax = nCoordHeight / 2;
2125 EnhancedCustomShapeParameter aRangeYMaximum;
2126 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMaximum, nRangeYMax,
2127 bool( nFlags & SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL ), false );
2128 aProp.Name = "RangeYMaximum";
2129 aProp.Value <<= aRangeYMaximum;
2130 aHandlePropVec.push_back( aProp );
2133 if ( nFlags & SvxMSDffHandleFlags::RADIUS_RANGE )
2135 if ( static_cast<sal_uInt32>(nRangeXMin) != 0x7fffffff )
2137 if ( nRangeXMin == 2 )
2138 nRangeXMin = nCoordWidth / 2;
2139 EnhancedCustomShapeParameter aRadiusRangeMinimum;
2140 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMinimum, nRangeXMin,
2141 bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL ), true );
2142 aProp.Name = "RadiusRangeMinimum";
2143 aProp.Value <<= aRadiusRangeMinimum;
2144 aHandlePropVec.push_back( aProp );
2146 if ( static_cast<sal_uInt32>(nRangeXMax) != 0x80000000 )
2148 if ( nRangeXMax == 2 )
2149 nRangeXMax = nCoordWidth / 2;
2150 EnhancedCustomShapeParameter aRadiusRangeMaximum;
2151 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMaximum, nRangeXMax,
2152 bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL ), false );
2153 aProp.Name = "RadiusRangeMaximum";
2154 aProp.Value <<= aRadiusRangeMaximum;
2155 aHandlePropVec.push_back( aProp );
2158 aHandlesRange[ i ] = comphelper::containerToSequence(aHandlePropVec);
2160 // pushing the whole Handles element
2161 aProp.Name = "Handles";
2162 aProp.Value <<= aHandles;
2163 aPropVec.push_back( aProp );
2166 else
2168 const mso_CustomShape* pDefCustomShape = GetCustomShapeContent( rObjData.eShapeType );
2169 if (pDefCustomShape && !pDefCustomShape->pHandles.empty())
2171 // TODO: This is very similar to EscherPropertyContainer::LookForPolarHandles
2172 sal_uInt32 i, nCnt = pDefCustomShape->pHandles.size();
2173 for (i = 0; i < nCnt; i++)
2175 const SvxMSDffHandle* pData = &pDefCustomShape->pHandles[i];
2176 if ( pData->nFlags & SvxMSDffHandleFlags::POLAR )
2178 if ( ( pData->nPositionY >= 0x256 ) || ( pData->nPositionY <= 0x107 ) )
2179 nAdjustmentsWhichNeedsToBeConverted |= ( 1U << i );
2185 // "Path" PropertySequence element
2188 PropVec aPathPropVec;
2190 // "Path/ExtrusionAllowed"
2191 if ( IsHardAttribute( DFF_Prop_f3DOK ) )
2193 bool bExtrusionAllowed = ( GetPropertyValue( DFF_Prop_fFillOK, 0 ) & 16 ) != 0;
2194 aProp.Name = "ExtrusionAllowed";
2195 aProp.Value <<= bExtrusionAllowed;
2196 aPathPropVec.push_back( aProp );
2198 // "Path/ConcentricGradientFillAllowed"
2199 if ( IsHardAttribute( DFF_Prop_fFillShadeShapeOK ) )
2201 bool bConcentricGradientFillAllowed = ( GetPropertyValue( DFF_Prop_fFillOK, 0 ) & 2 ) != 0;
2202 aProp.Name = "ConcentricGradientFillAllowed";
2203 aProp.Value <<= bConcentricGradientFillAllowed;
2204 aPathPropVec.push_back( aProp );
2206 // "Path/TextPathAllowed"
2207 if ( IsHardAttribute( DFF_Prop_fGtextOK ) || ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x4000 ) )
2209 bool bTextPathAllowed = ( GetPropertyValue( DFF_Prop_fFillOK, 0 ) & 4 ) != 0;
2210 aProp.Name = "TextPathAllowed";
2211 aProp.Value <<= bTextPathAllowed;
2212 aPathPropVec.push_back( aProp );
2214 // Path/Coordinates
2215 if ( IsProperty( DFF_Prop_pVertices ) )
2217 css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aCoordinates;
2218 sal_uInt16 nNumElemVert = 0;
2219 sal_uInt16 nElemSizeVert = 8;
2221 if ( SeekToContent( DFF_Prop_pVertices, rIn ) )
2223 sal_uInt16 nNumElemMemVert = 0;
2224 rIn.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert );
2225 // If this value is 0xFFF0 then this record is an array of truncated 8 byte elements. Only the 4
2226 // low-order bytes are recorded
2227 if (nElemSizeVert == 0xFFF0)
2228 nElemSizeVert = 4;
2230 //sanity check that the stream is long enough to fulfill nNumElem * nElemSize;
2231 bool bImport = nElemSizeVert && (rIn.remainingSize() / nElemSizeVert >= nNumElemVert);
2232 if (bImport)
2234 aCoordinates.realloc( nNumElemVert );
2235 for (auto& rCoordinate : asNonConstRange(aCoordinates))
2237 sal_Int32 nX(0), nY(0);
2239 if ( nElemSizeVert == 8 )
2241 rIn.ReadInt32( nX )
2242 .ReadInt32( nY );
2244 else
2246 // The mso-spt19 (arc) uses this. But it needs unsigned integer. I don't
2247 // know if other shape types also need it. They can be added as necessary.
2248 bool bNeedsUnsigned = rObjData.eShapeType == mso_sptArc;
2249 if (bNeedsUnsigned)
2251 sal_uInt16 nTmpA(0), nTmpB(0);
2252 rIn.ReadUInt16(nTmpA)
2253 .ReadUInt16(nTmpB);
2254 nX = nTmpA;
2255 nY = nTmpB;
2257 else
2259 sal_Int16 nTmpA(0), nTmpB(0);
2260 rIn.ReadInt16( nTmpA )
2261 .ReadInt16( nTmpB );
2262 nX = nTmpA;
2263 nY = nTmpB;
2266 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rCoordinate.First, nX );
2267 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rCoordinate.Second, nY );
2270 aProp.Name = "Coordinates";
2271 aProp.Value <<= aCoordinates;
2272 aPathPropVec.push_back( aProp );
2274 // Path/Segments
2275 if ( IsProperty( DFF_Prop_pSegmentInfo ) )
2277 css::uno::Sequence< css::drawing::EnhancedCustomShapeSegment > aSegments;
2279 sal_uInt16 nNumElemSeg = 0;
2281 if ( SeekToContent( DFF_Prop_pSegmentInfo, rIn ) )
2283 sal_uInt16 nNumElemMemSeg = 0;
2284 sal_uInt16 nElemSizeSeg = 2;
2285 rIn.ReadUInt16( nNumElemSeg ).ReadUInt16( nNumElemMemSeg ).ReadUInt16( nElemSizeSeg );
2287 sal_uInt64 nMaxEntriesPossible = rIn.remainingSize() / sizeof(sal_uInt16);
2288 if (nNumElemSeg > nMaxEntriesPossible)
2290 SAL_WARN("filter.ms", "NumElem list is longer than remaining bytes, ppt or parser is wrong");
2291 nNumElemSeg = nMaxEntriesPossible;
2293 if ( nNumElemSeg )
2295 aSegments.realloc( nNumElemSeg );
2296 for (auto& rSegment : asNonConstRange(aSegments))
2298 sal_uInt16 nTmp(0);
2299 rIn.ReadUInt16( nTmp );
2300 sal_Int16 nCommand = EnhancedCustomShapeSegmentCommand::UNKNOWN;
2301 sal_Int16 nCnt = static_cast<sal_Int16>( nTmp & 0x1fff );//Last 13 bits for segment points number
2302 switch( nTmp >> 13 )//First 3 bits for command type
2304 case 0x0:
2305 nCommand = EnhancedCustomShapeSegmentCommand::LINETO;
2306 if ( !nCnt ) nCnt = 1;
2307 break;
2308 case 0x1:
2309 nCommand = EnhancedCustomShapeSegmentCommand::CURVETO;
2310 if ( !nCnt ) nCnt = 1;
2311 break;
2312 case 0x2:
2313 nCommand = EnhancedCustomShapeSegmentCommand::MOVETO;
2314 if ( !nCnt ) nCnt = 1;
2315 break;
2316 case 0x3:
2317 nCommand = EnhancedCustomShapeSegmentCommand::CLOSESUBPATH;
2318 nCnt = 0;
2319 break;
2320 case 0x4:
2321 nCommand = EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
2322 nCnt = 0;
2323 break;
2324 case 0x5:
2325 case 0x6:
2327 switch ( ( nTmp >> 8 ) & 0x1f )//5 bits next to command type is for path escape type
2329 case 0x0:
2331 //It is msopathEscapeExtension which is transformed into LINETO.
2332 //If issue happens, I think this part can be comment so that it will be taken as unknown command.
2333 //When export, origin data will be export without any change.
2334 nCommand = EnhancedCustomShapeSegmentCommand::LINETO;
2335 if ( !nCnt )
2336 nCnt = 1;
2338 break;
2339 case 0x1:
2341 nCommand = EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO;
2342 nCnt = ( nTmp & 0xff ) / 3;
2344 break;
2345 case 0x2:
2347 nCommand = EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE;
2348 nCnt = ( nTmp & 0xff ) / 3;
2350 break;
2351 case 0x3:
2353 nCommand = EnhancedCustomShapeSegmentCommand::ARCTO;
2354 nCnt = ( nTmp & 0xff ) >> 2;
2356 break;
2357 case 0x4:
2359 nCommand = EnhancedCustomShapeSegmentCommand::ARC;
2360 nCnt = ( nTmp & 0xff ) >> 2;
2362 break;
2363 case 0x5:
2365 nCommand = EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO;
2366 nCnt = ( nTmp & 0xff ) >> 2;
2368 break;
2369 case 0x6:
2371 nCommand = EnhancedCustomShapeSegmentCommand::CLOCKWISEARC;
2372 nCnt = ( nTmp & 0xff ) >> 2;
2374 break;
2375 case 0x7:
2377 nCommand = EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX;
2378 nCnt = nTmp & 0xff;
2380 break;
2381 case 0x8:
2383 nCommand = EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY;
2384 nCnt = nTmp & 0xff;
2386 break;
2387 case 0xa: nCommand = EnhancedCustomShapeSegmentCommand::NOFILL; nCnt = 0; break;
2388 case 0xb: nCommand = EnhancedCustomShapeSegmentCommand::NOSTROKE; nCnt = 0; break;
2391 break;
2393 // if the command is unknown, we will store all the data in nCnt, so it will be possible to export without loss
2394 if ( nCommand == EnhancedCustomShapeSegmentCommand::UNKNOWN )
2395 nCnt = static_cast<sal_Int16>(nTmp);
2396 rSegment.Command = nCommand;
2397 rSegment.Count = nCnt;
2400 aProp.Name = "Segments";
2401 aProp.Value <<= aSegments;
2402 aPathPropVec.push_back( aProp );
2404 // Path/StretchX
2405 if ( IsProperty( DFF_Prop_stretchPointX ) )
2407 sal_Int32 nStretchX = GetPropertyValue( DFF_Prop_stretchPointX, 0 );
2408 aProp.Name = "StretchX";
2409 aProp.Value <<= nStretchX;
2410 aPathPropVec.push_back( aProp );
2412 // Path/StretchX
2413 if ( IsProperty( DFF_Prop_stretchPointY ) )
2415 sal_Int32 nStretchY = GetPropertyValue( DFF_Prop_stretchPointY, 0 );
2416 aProp.Name = "StretchY";
2417 aProp.Value <<= nStretchY;
2418 aPathPropVec.push_back( aProp );
2420 // Path/TextFrames
2421 if ( IsProperty( DFF_Prop_textRectangles ) )
2423 sal_uInt16 nNumElem = 0;
2424 sal_uInt16 nElemSize = 16;
2426 if ( SeekToContent( DFF_Prop_textRectangles, rIn ) )
2428 sal_uInt16 nNumElemMem = 0;
2429 rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemMem ).ReadUInt16( nElemSize );
2431 bool bImport = false;
2432 if (nElemSize == 16)
2434 //sanity check that the stream is long enough to fulfill nNumElem * nElemSize;
2435 bImport = rIn.remainingSize() / nElemSize >= nNumElem;
2437 if (bImport)
2439 css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aTextFrames( nNumElem );
2440 for (auto& rTextFrame : asNonConstRange(aTextFrames))
2442 sal_Int32 nLeft(0), nTop(0), nRight(0), nBottom(0);
2444 rIn.ReadInt32( nLeft )
2445 .ReadInt32( nTop )
2446 .ReadInt32( nRight )
2447 .ReadInt32( nBottom );
2449 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rTextFrame.TopLeft.First, nLeft );
2450 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rTextFrame.TopLeft.Second, nTop );
2451 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rTextFrame.BottomRight.First, nRight );
2452 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rTextFrame.BottomRight.Second, nBottom);
2454 aProp.Name = "TextFrames";
2455 aProp.Value <<= aTextFrames;
2456 aPathPropVec.push_back( aProp );
2459 //Path/GluePoints
2460 if ( IsProperty( DFF_Prop_connectorPoints ) )
2462 css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aGluePoints;
2463 sal_uInt16 nNumElemVert = 0;
2464 sal_uInt16 nElemSizeVert = 8;
2466 if ( SeekToContent( DFF_Prop_connectorPoints, rIn ) )
2468 sal_uInt16 nNumElemMemVert = 0;
2469 rIn.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert );
2470 // If this value is 0xFFF0 then this record is an array of truncated 8 byte elements. Only the 4
2471 // low-order bytes are recorded
2472 if (nElemSizeVert == 0xFFF0)
2473 nElemSizeVert = 4;
2476 // sanity check that the stream is long enough to fulfill nNumElemVert * nElemSizeVert;
2477 bool bImport = nElemSizeVert && (rIn.remainingSize() / nElemSizeVert >= nNumElemVert);
2478 if (bImport)
2480 aGluePoints.realloc( nNumElemVert );
2481 for (auto& rGluePoint : asNonConstRange(aGluePoints))
2483 sal_Int32 nX(0), nY(0);
2484 if ( nElemSizeVert == 8 )
2486 rIn.ReadInt32( nX )
2487 .ReadInt32( nY );
2489 else
2491 sal_Int16 nTmpA(0), nTmpB(0);
2493 rIn.ReadInt16( nTmpA )
2494 .ReadInt16( nTmpB );
2496 nX = nTmpA;
2497 nY = nTmpB;
2499 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rGluePoint.First, nX );
2500 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rGluePoint.Second, nY );
2503 aProp.Name = "GluePoints";
2504 aProp.Value <<= aGluePoints;
2505 aPathPropVec.push_back( aProp );
2507 if ( IsProperty( DFF_Prop_connectorType ) )
2509 sal_Int16 nGluePointType = static_cast<sal_uInt16>(GetPropertyValue( DFF_Prop_connectorType, 0 ));
2510 aProp.Name = "GluePointType";
2511 aProp.Value <<= nGluePointType;
2512 aPathPropVec.push_back( aProp );
2514 // pushing the whole Path element
2515 if ( !aPathPropVec.empty() )
2517 aProp.Name = "Path";
2518 aProp.Value <<= comphelper::containerToSequence(aPathPropVec);
2519 aPropVec.push_back( aProp );
2523 // "TextPath" PropertySequence element
2525 bool bTextPathOn = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x4000 ) != 0;
2526 if ( bTextPathOn )
2528 PropVec aTextPathPropVec;
2530 // TextPath
2531 aProp.Name = "TextPath";
2532 aProp.Value <<= bTextPathOn;
2533 aTextPathPropVec.push_back( aProp );
2535 // TextPathMode
2536 bool bTextPathFitPath = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x100 ) != 0;
2538 bool bTextPathFitShape;
2539 if ( IsHardAttribute( DFF_Prop_gtextFStretch ) )
2540 bTextPathFitShape = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x400 ) != 0;
2541 else
2543 bTextPathFitShape = true;
2544 switch( rObjData.eShapeType )
2546 case mso_sptTextArchUpCurve :
2547 case mso_sptTextArchDownCurve :
2548 case mso_sptTextCircleCurve :
2549 case mso_sptTextButtonCurve :
2550 bTextPathFitShape = false;
2551 break;
2552 default : break;
2555 EnhancedCustomShapeTextPathMode eTextPathMode( EnhancedCustomShapeTextPathMode_NORMAL );
2556 if ( bTextPathFitShape )
2557 eTextPathMode = EnhancedCustomShapeTextPathMode_SHAPE;
2558 else if ( bTextPathFitPath )
2559 eTextPathMode = EnhancedCustomShapeTextPathMode_PATH;
2560 aProp.Name = "TextPathMode";
2561 aProp.Value <<= eTextPathMode;
2562 aTextPathPropVec.push_back( aProp );
2564 // ScaleX
2565 bool bTextPathScaleX = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x40 ) != 0;
2566 aProp.Name = "ScaleX";
2567 aProp.Value <<= bTextPathScaleX;
2568 aTextPathPropVec.push_back( aProp );
2569 // SameLetterHeights
2570 bool bSameLetterHeight = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x80 ) != 0;
2571 aProp.Name = "SameLetterHeights";
2572 aProp.Value <<= bSameLetterHeight;
2573 aTextPathPropVec.push_back( aProp );
2575 // pushing the whole TextPath element
2576 aProp.Name = "TextPath";
2577 aProp.Value <<= comphelper::containerToSequence(aTextPathPropVec);
2578 aPropVec.push_back( aProp );
2581 // "AdjustmentValues" // The AdjustmentValues are imported at last, because depending to the type of the
2582 //////////////////////// handle (POLAR) we will convert the adjustment value from a fixed float to double
2584 // checking the last used adjustment handle, so we can determine how many handles are to allocate
2585 sal_uInt32 i = DFF_Prop_adjust10Value;
2586 while ( ( i >= DFF_Prop_adjustValue ) && !IsProperty( i ) )
2587 i--;
2588 sal_Int32 nAdjustmentValues = ( i - DFF_Prop_adjustValue ) + 1;
2589 if ( nAdjustmentValues )
2591 uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentSeq( nAdjustmentValues );
2592 auto pAdjustmentSeq = aAdjustmentSeq.getArray();
2593 while( --nAdjustmentValues >= 0 )
2595 sal_Int32 nValue = 0;
2596 beans::PropertyState ePropertyState = beans::PropertyState_DEFAULT_VALUE;
2597 if ( IsProperty( i ) )
2599 nValue = GetPropertyValue( i, 0 );
2600 ePropertyState = beans::PropertyState_DIRECT_VALUE;
2602 if ( nAdjustmentsWhichNeedsToBeConverted & ( 1 << ( i - DFF_Prop_adjustValue ) ) )
2604 double fValue = nValue;
2605 fValue /= 65536;
2606 pAdjustmentSeq[ nAdjustmentValues ].Value <<= fValue;
2608 else
2609 pAdjustmentSeq[ nAdjustmentValues ].Value <<= nValue;
2610 pAdjustmentSeq[ nAdjustmentValues ].State = ePropertyState;
2611 i--;
2613 aProp.Name = "AdjustmentValues";
2614 aProp.Value <<= aAdjustmentSeq;
2615 aPropVec.push_back( aProp );
2618 // creating the whole property set
2619 rSet.Put( SdrCustomShapeGeometryItem( comphelper::containerToSequence(aPropVec) ) );
2622 void DffPropertyReader::ApplyAttributes( SvStream& rIn, SfxItemSet& rSet ) const
2624 DffRecordHeader aHdTemp;
2625 DffObjData aDffObjTemp( aHdTemp, tools::Rectangle(), 0 );
2626 ApplyAttributes( rIn, rSet, aDffObjTemp );
2629 void DffPropertyReader::ApplyAttributes( SvStream& rIn, SfxItemSet& rSet, DffObjData const & rObjData ) const
2631 bool bHasShadow = false;
2632 bool bNonZeroShadowOffset = false;
2634 if ( IsProperty( DFF_Prop_gtextSize ) )
2635 rSet.Put( SvxFontHeightItem( rManager.ScalePt( GetPropertyValue( DFF_Prop_gtextSize, 0 ) ), 100, EE_CHAR_FONTHEIGHT ) );
2636 sal_uInt32 nFontAttributes = GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 );
2637 if ( nFontAttributes & 0x20 )
2638 rSet.Put( SvxWeightItem( (nFontAttributes & 0x20) ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT ) );
2639 if ( nFontAttributes & 0x10 )
2640 rSet.Put( SvxPostureItem( (nFontAttributes & 0x10) ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC ) );
2641 if ( nFontAttributes & 0x08 )
2642 rSet.Put( SvxUnderlineItem( (nFontAttributes & 0x08) ? LINESTYLE_SINGLE : LINESTYLE_NONE, EE_CHAR_UNDERLINE ) );
2643 if ( nFontAttributes & 0x40 )
2644 rSet.Put( SvxShadowedItem( (nFontAttributes & 0x40) != 0, EE_CHAR_SHADOW ) );
2645 // if ( nFontAttributes & 0x02 )
2646 // rSet.Put( SvxCaseMapItem( nFontAttributes & 0x02 ? SvxCaseMap::SmallCaps : SvxCaseMap::NotMapped ) );
2647 if ( nFontAttributes & 0x01 )
2648 rSet.Put( SvxCrossedOutItem( (nFontAttributes & 0x01) ? STRIKEOUT_SINGLE : STRIKEOUT_NONE, EE_CHAR_STRIKEOUT ) );
2649 if ( IsProperty( DFF_Prop_fillColor ) )
2650 rSet.Put( XFillColorItem( OUString(), rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillColor, 0 ), DFF_Prop_fillColor ) ) );
2651 if ( IsProperty( DFF_Prop_shadowColor ) )
2652 rSet.Put( makeSdrShadowColorItem( rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_shadowColor, 0 ), DFF_Prop_shadowColor ) ) );
2653 else
2655 //The default value for this property is 0x00808080
2656 rSet.Put( makeSdrShadowColorItem( rManager.MSO_CLR_ToColor( 0x00808080, DFF_Prop_shadowColor ) ) );
2658 if ( IsProperty( DFF_Prop_shadowOpacity ) )
2659 rSet.Put( makeSdrShadowTransparenceItem( static_cast<sal_uInt16>( ( 0x10000 - GetPropertyValue( DFF_Prop_shadowOpacity, 0 ) ) / 655 ) ) );
2660 if ( IsProperty( DFF_Prop_shadowOffsetX ) )
2662 sal_Int32 nVal = static_cast< sal_Int32 >( GetPropertyValue( DFF_Prop_shadowOffsetX, 0 ) );
2663 rManager.ScaleEmu( nVal );
2664 rSet.Put( makeSdrShadowXDistItem( nVal ) );
2665 bNonZeroShadowOffset = ( nVal > 0 );
2667 if ( IsProperty( DFF_Prop_shadowOffsetY ) )
2669 sal_Int32 nVal = static_cast< sal_Int32 >( GetPropertyValue( DFF_Prop_shadowOffsetY, 0 ) );
2670 rManager.ScaleEmu( nVal );
2671 rSet.Put( makeSdrShadowYDistItem( nVal ) );
2672 bNonZeroShadowOffset = ( nVal > 0 );
2674 if ( IsProperty( DFF_Prop_fshadowObscured ) )
2676 bHasShadow = ( GetPropertyValue( DFF_Prop_fshadowObscured, 0 ) & 2 ) != 0;
2677 if ( bHasShadow )
2679 if ( !IsProperty( DFF_Prop_shadowOffsetX ) )
2680 rSet.Put( makeSdrShadowXDistItem( 35 ) );
2681 if ( !IsProperty( DFF_Prop_shadowOffsetY ) )
2682 rSet.Put( makeSdrShadowYDistItem( 35 ) );
2685 if ( IsProperty( DFF_Prop_shadowType ) )
2687 auto eShadowType = GetPropertyValue(DFF_Prop_shadowType, 0);
2688 if( eShadowType != mso_shadowOffset && !bNonZeroShadowOffset )
2690 //0.12" == 173 twip == 302 100mm
2691 sal_uInt32 nDist = rManager.pSdrModel->GetScaleUnit() == MapUnit::MapTwip ? 173: 302;
2692 rSet.Put( makeSdrShadowXDistItem( nDist ) );
2693 rSet.Put( makeSdrShadowYDistItem( nDist ) );
2696 if ( bHasShadow )
2698 static bool bCheckShadow(false); // loplugin:constvars:ignore
2700 // #i124477# Found no reason not to set shadow, esp. since it is applied to evtl. existing text
2701 // and will lead to an error if in PPT someone used text and added the object shadow to the
2702 // object carrying that text. I found no cases where this leads to problems (the old bugtracker
2703 // task #160376# from sj is unfortunately no longer available). Keeping the code for now
2704 // to allow easy fallback when this shows problems in the future
2705 if(bCheckShadow)
2707 // #160376# sj: activating shadow only if fill and or linestyle is used
2708 // this is required because of the latest drawing layer core changes.
2709 // #i104085# is related to this.
2710 sal_uInt32 nLineFlags(GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 ));
2711 if(!IsHardAttribute( DFF_Prop_fLine ) && !IsCustomShapeStrokedByDefault( rObjData.eShapeType ))
2712 nLineFlags &= ~0x08;
2713 sal_uInt32 nFillFlags(GetPropertyValue( DFF_Prop_fNoFillHitTest, 0 ));
2714 if(!IsHardAttribute( DFF_Prop_fFilled ) && !IsCustomShapeFilledByDefault( rObjData.eShapeType ))
2715 nFillFlags &= ~0x10;
2716 if ( nFillFlags & 0x10 )
2718 auto eMSO_FillType = GetPropertyValue(DFF_Prop_fillType, mso_fillSolid);
2719 switch( eMSO_FillType )
2721 case mso_fillSolid :
2722 case mso_fillPattern :
2723 case mso_fillTexture :
2724 case mso_fillPicture :
2725 case mso_fillShade :
2726 case mso_fillShadeCenter :
2727 case mso_fillShadeShape :
2728 case mso_fillShadeScale :
2729 case mso_fillShadeTitle :
2730 break;
2731 default:
2732 nFillFlags &=~0x10; // no fillstyle used
2733 break;
2736 if ( ( ( nLineFlags & 0x08 ) == 0 ) && ( ( nFillFlags & 0x10 ) == 0 ) && ( rObjData.eShapeType != mso_sptPictureFrame )) // if there is no fillstyle and linestyle
2737 bHasShadow = false; // we are turning shadow off.
2740 if ( bHasShadow )
2741 rSet.Put( makeSdrShadowItem( bHasShadow ) );
2743 ApplyLineAttributes( rSet, rObjData.eShapeType ); // #i28269#
2744 ApplyFillAttributes( rIn, rSet, rObjData );
2745 if ( rObjData.eShapeType != mso_sptNil || IsProperty( DFF_Prop_pVertices ) )
2747 ApplyCustomShapeGeometryAttributes( rIn, rSet, rObjData );
2748 ApplyCustomShapeTextAttributes( rSet );
2749 if ( rManager.GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_EXCEL )
2751 if ( mnFix16Angle || ( rObjData.nSpFlags & ShapeFlag::FlipV ) )
2752 CheckAndCorrectExcelTextRotation( rIn, rSet, rObjData );
2757 void DffPropertyReader::CheckAndCorrectExcelTextRotation( SvStream& rIn, SfxItemSet& rSet, DffObjData const & rObjData ) const
2759 bool bRotateTextWithShape = rObjData.bRotateTextWithShape;
2760 if ( rObjData.bOpt2 ) // sj: #158494# is the second property set available ? if then we have to check the xml data of
2761 { // the shape, because the textrotation of Excel 2003 and greater versions is stored there
2762 // (upright property of the textbox)
2763 if ( rManager.pSecPropSet->SeekToContent( DFF_Prop_metroBlob, rIn ) )
2765 sal_uInt32 nLen = rManager.pSecPropSet->GetPropertyValue( DFF_Prop_metroBlob, 0 );
2766 if ( nLen )
2768 css::uno::Sequence< sal_Int8 > aXMLDataSeq( nLen );
2769 rIn.ReadBytes(aXMLDataSeq.getArray(), nLen);
2770 css::uno::Reference< css::io::XInputStream > xInputStream
2771 ( new ::comphelper::SequenceInputStream( aXMLDataSeq ) );
2774 const css::uno::Reference< css::uno::XComponentContext >& xContext( ::comphelper::getProcessComponentContext() );
2775 css::uno::Reference< css::embed::XStorage > xStorage
2776 ( ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream(
2777 OFOPXML_STORAGE_FORMAT_STRING, xInputStream, xContext, true ) );
2778 if ( xStorage.is() )
2780 css::uno::Reference< css::embed::XStorage >
2781 xStorageDRS( xStorage->openStorageElement( u"drs"_ustr, css::embed::ElementModes::SEEKABLEREAD ) );
2782 if ( xStorageDRS.is() )
2784 css::uno::Reference< css::io::XStream > xShapeXMLStream( xStorageDRS->openStreamElement( u"shapexml.xml"_ustr, css::embed::ElementModes::SEEKABLEREAD ) );
2785 if ( xShapeXMLStream.is() )
2787 css::uno::Reference< css::io::XInputStream > xShapeXMLInputStream( xShapeXMLStream->getInputStream() );
2788 if ( xShapeXMLInputStream.is() )
2790 css::uno::Sequence< sal_Int8 > aSeq;
2791 sal_Int32 nBytesRead = xShapeXMLInputStream->readBytes( aSeq, 0x7fffffff );
2792 if ( nBytesRead )
2793 { // for only one property I spare to use a XML parser at this point, this
2794 // should be enhanced if needed
2796 bRotateTextWithShape = true; // using the correct xml default
2797 const char* pArry = reinterpret_cast< char* >( aSeq.getArray() );
2798 const char* const pUpright = "upright=";
2799 const char* pEnd = pArry + nBytesRead;
2800 const char* pPtr = pArry;
2801 while( ( pPtr + 12 ) < pEnd )
2803 if ( !memcmp( pUpright, pPtr, 8 ) )
2805 bRotateTextWithShape = ( pPtr[ 9 ] != '1' ) && ( pPtr[ 9 ] != 't' );
2806 break;
2808 else
2809 pPtr++;
2817 catch( css::uno::Exception& )
2823 if ( bRotateTextWithShape )
2824 return;
2826 const css::uno::Any* pAny;
2827 SdrCustomShapeGeometryItem aGeometryItem(rSet.Get( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
2828 static constexpr OUString sTextRotateAngle( u"TextRotateAngle"_ustr );
2829 pAny = aGeometryItem.GetPropertyValueByName( sTextRotateAngle );
2830 double fExtraTextRotateAngle = 0.0;
2831 if ( pAny )
2832 *pAny >>= fExtraTextRotateAngle;
2834 if ( rManager.mnFix16Angle )
2835 fExtraTextRotateAngle += toDegrees(mnFix16Angle);
2836 if ( rObjData.nSpFlags & ShapeFlag::FlipV )
2837 fExtraTextRotateAngle -= 180.0;
2839 css::beans::PropertyValue aTextRotateAngle;
2840 aTextRotateAngle.Name = sTextRotateAngle;
2841 aTextRotateAngle.Value <<= fExtraTextRotateAngle;
2842 aGeometryItem.SetPropertyValue( aTextRotateAngle );
2843 rSet.Put( aGeometryItem );
2847 void DffPropertyReader::ImportGradientColor( SfxItemSet& aSet, sal_uInt32 eMSO_FillType, double dTrans , double dBackTrans) const
2849 //MS Focus prop will impact the start and end color position. And AOO does not
2850 //support this prop. So need some swap for the two color to keep fidelity with AOO and MS shape.
2851 //So below var is defined.
2852 sal_Int32 nChgColors = 0;
2853 sal_Int32 nAngleFix16 = GetPropertyValue( DFF_Prop_fillAngle, 0 );
2854 if(nAngleFix16 >= 0)
2855 nChgColors ^= 1;
2857 //Translate a MS clockwise(+) or count clockwise angle(-) into an AOO count clock wise angle
2858 Degree10 nAngle( 3600_deg10 - to<Degree10>( Fix16ToAngle(nAngleFix16) ) );
2859 //Make sure this angle belongs to 0~3600
2860 while ( nAngle >= 3600_deg10 ) nAngle -= 3600_deg10;
2861 while ( nAngle < 0_deg10 ) nAngle += 3600_deg10;
2863 //Rotate angle
2864 if ( mbRotateGranientFillWithAngle )
2866 sal_Int32 nRotateAngle = GetPropertyValue( DFF_Prop_Rotation, 0 );
2867 //nAngle is a clockwise angle. If nRotateAngle is a clockwise angle, then gradient needs to be rotated a little less
2868 //or it needs to be rotated a little more
2869 nAngle -= to<Degree10>(Fix16ToAngle(nRotateAngle));
2871 while ( nAngle >= 3600_deg10 ) nAngle -= 3600_deg10;
2872 while ( nAngle < 0_deg10 ) nAngle += 3600_deg10;
2874 css::awt::GradientStyle eGrad = css::awt::GradientStyle_LINEAR;
2876 sal_Int32 nFocus = GetPropertyValue( DFF_Prop_fillFocus, 0 );
2877 if ( !nFocus )
2878 nChgColors ^= 1;
2879 else if ( nFocus < 0 )//If it is a negative focus, the color will be swapped
2881 nFocus = o3tl::saturating_toggle_sign(nFocus);
2882 nChgColors ^= 1;
2885 if( nFocus > 40 && nFocus < 60 )
2887 eGrad = css::awt::GradientStyle_AXIAL;//A axial gradient other than linear
2888 nChgColors ^= 1;
2890 //if the type is linear or axial, just save focus to nFocusX and nFocusY for export
2891 //Core function does no need them. They serve for rect gradient(CenterXY).
2892 sal_uInt16 nFocusX = static_cast<sal_uInt16>(nFocus);
2893 sal_uInt16 nFocusY = static_cast<sal_uInt16>(nFocus);
2895 switch( eMSO_FillType )
2897 case mso_fillShadeShape :
2899 eGrad = css::awt::GradientStyle_RECT;
2900 nFocusY = nFocusX = 50;
2901 nChgColors ^= 1;
2903 break;
2904 case mso_fillShadeCenter :
2906 eGrad = css::awt::GradientStyle_RECT;
2907 //A MS fillTo prop specifies the relative position of the left boundary
2908 //of the center rectangle in a concentric shaded fill. Use 100 or 0 to keep fidelity
2909 nFocusX=(GetPropertyValue( DFF_Prop_fillToRight, 0 )==0x10000) ? 100 : 0;
2910 nFocusY=(GetPropertyValue( DFF_Prop_fillToBottom,0 )==0x10000) ? 100 : 0;
2911 nChgColors ^= 1;
2913 break;
2914 default: break;
2917 Color aCol1( rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillColor ) );
2918 Color aCol2( rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillBackColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillBackColor ) );
2919 if ( nChgColors )
2921 //Swap start and end color
2922 Color aZwi( aCol1 );
2923 aCol1 = aCol2;
2924 aCol2 = aZwi;
2925 //Swap two colors' transparency
2926 std::swap( dTrans, dBackTrans );
2929 //Construct gradient item
2930 basegfx::BGradient aGrad(
2931 basegfx::BColorStops(aCol2.getBColor(), aCol1.getBColor()),
2932 eGrad, nAngle, nFocusX, nFocusY );
2933 //Intensity has been merged into color. So here just set is as 100
2934 aGrad.SetStartIntens( 100 );
2935 aGrad.SetEndIntens( 100 );
2936 aSet.Put( XFillGradientItem( OUString(), aGrad ) );
2937 //Construct transparency item. This item can coordinate with both solid and gradient.
2938 if ( dTrans < 1.0 || dBackTrans < 1.0 )
2940 sal_uInt8 nStartCol = static_cast<sal_uInt8>( (1 - dTrans )* 255 );
2941 sal_uInt8 nEndCol = static_cast<sal_uInt8>( ( 1- dBackTrans ) * 255 );
2942 aCol1 = Color(nStartCol, nStartCol, nStartCol);
2943 aCol2 = Color(nEndCol, nEndCol, nEndCol);
2945 basegfx::BGradient aGrad2(
2946 basegfx::BColorStops(aCol2.getBColor(), aCol1.getBColor()),
2947 eGrad, nAngle, nFocusX, nFocusY );
2948 aSet.Put( XFillFloatTransparenceItem( OUString(), aGrad2 ) );
2953 //- Record Manager ----------------------------------------------------------
2956 DffRecordList::DffRecordList( DffRecordList* pList ) :
2957 nCount ( 0 ),
2958 nCurrent ( 0 ),
2959 pPrev ( pList )
2961 if ( pList )
2962 pList->pNext.reset( this );
2965 DffRecordList::~DffRecordList()
2969 DffRecordManager::DffRecordManager() :
2970 DffRecordList ( nullptr ),
2971 pCList ( static_cast<DffRecordList*>(this) )
2975 DffRecordManager::DffRecordManager( SvStream& rIn ) :
2976 DffRecordList ( nullptr ),
2977 pCList ( static_cast<DffRecordList*>(this) )
2979 Consume( rIn );
2982 void DffRecordManager::Consume( SvStream& rIn, sal_uInt32 nStOfs )
2984 Clear();
2985 sal_uInt64 nOldPos = rIn.Tell();
2986 if ( !nStOfs )
2988 DffRecordHeader aHd;
2989 bool bOk = ReadDffRecordHeader( rIn, aHd );
2990 if (bOk && aHd.nRecVer == DFF_PSFLAG_CONTAINER)
2991 nStOfs = aHd.GetRecEndFilePos();
2993 if ( !nStOfs )
2994 return;
2996 pCList = this;
2997 while ( pCList->pNext )
2998 pCList = pCList->pNext.get();
2999 while (rIn.good() && ( ( rIn.Tell() + 8 ) <= nStOfs ))
3001 if ( pCList->nCount == DFF_RECORD_MANAGER_BUF_SIZE )
3002 pCList = new DffRecordList( pCList );
3003 if (!ReadDffRecordHeader(rIn, pCList->mHd[ pCList->nCount ]))
3004 break;
3005 bool bSeekSucceeded = pCList->mHd[ pCList->nCount++ ].SeekToEndOfRecord(rIn);
3006 if (!bSeekSucceeded)
3007 break;
3009 rIn.Seek( nOldPos );
3012 void DffRecordManager::Clear()
3014 pCList = this;
3015 pNext.reset();
3016 nCurrent = 0;
3017 nCount = 0;
3020 DffRecordHeader* DffRecordManager::Current()
3022 DffRecordHeader* pRet = nullptr;
3023 if ( pCList->nCurrent < pCList->nCount )
3024 pRet = &pCList->mHd[ pCList->nCurrent ];
3025 return pRet;
3028 DffRecordHeader* DffRecordManager::First()
3030 DffRecordHeader* pRet = nullptr;
3031 pCList = this;
3032 if ( pCList->nCount )
3034 pCList->nCurrent = 0;
3035 pRet = &pCList->mHd[ 0 ];
3037 return pRet;
3040 DffRecordHeader* DffRecordManager::Next()
3042 DffRecordHeader* pRet = nullptr;
3043 sal_uInt32 nC = pCList->nCurrent + 1;
3044 if ( nC < pCList->nCount )
3046 pCList->nCurrent++;
3047 pRet = &pCList->mHd[ nC ];
3049 else if ( pCList->pNext )
3051 pCList = pCList->pNext.get();
3052 pCList->nCurrent = 0;
3053 pRet = &pCList->mHd[ 0 ];
3055 return pRet;
3058 DffRecordHeader* DffRecordManager::Prev()
3060 DffRecordHeader* pRet = nullptr;
3061 sal_uInt32 nCur = pCList->nCurrent;
3062 if ( !nCur && pCList->pPrev )
3064 pCList = pCList->pPrev;
3065 nCur = pCList->nCount;
3067 if ( nCur-- )
3069 pCList->nCurrent = nCur;
3070 pRet = &pCList->mHd[ nCur ];
3072 return pRet;
3075 DffRecordHeader* DffRecordManager::Last()
3077 DffRecordHeader* pRet = nullptr;
3078 while ( pCList->pNext )
3079 pCList = pCList->pNext.get();
3080 sal_uInt32 nCnt = pCList->nCount;
3081 if ( nCnt-- )
3083 pCList->nCurrent = nCnt;
3084 pRet = &pCList->mHd[ nCnt ];
3086 return pRet;
3089 bool DffRecordManager::SeekToContent( SvStream& rIn, sal_uInt16 nRecId, DffSeekToContentMode eMode )
3091 DffRecordHeader* pHd = GetRecordHeader( nRecId, eMode );
3092 if ( pHd )
3094 pHd->SeekToContent( rIn );
3095 return true;
3097 else
3098 return false;
3101 DffRecordHeader* DffRecordManager::GetRecordHeader( sal_uInt16 nRecId, DffSeekToContentMode eMode )
3103 sal_uInt32 nOldCurrent = pCList->nCurrent;
3104 DffRecordList* pOldList = pCList;
3105 DffRecordHeader* pHd;
3107 if ( eMode == SEEK_FROM_BEGINNING )
3108 pHd = First();
3109 else
3110 pHd = Next();
3112 while ( pHd )
3114 if ( pHd->nRecType == nRecId )
3115 break;
3116 pHd = Next();
3118 if ( !pHd && eMode == SEEK_FROM_CURRENT_AND_RESTART )
3120 DffRecordHeader* pBreak = &pOldList->mHd[ nOldCurrent ];
3121 pHd = First();
3122 if ( pHd )
3124 while ( pHd != pBreak )
3126 if ( pHd->nRecType == nRecId )
3127 break;
3128 pHd = Next();
3130 if ( pHd->nRecType != nRecId )
3131 pHd = nullptr;
3134 if ( !pHd )
3136 pCList = pOldList;
3137 pOldList->nCurrent = nOldCurrent;
3139 return pHd;
3143 // private methods
3146 bool CompareSvxMSDffShapeInfoById::operator() (
3147 std::shared_ptr<SvxMSDffShapeInfo> const& lhs,
3148 std::shared_ptr<SvxMSDffShapeInfo> const& rhs) const
3150 return lhs->nShapeId < rhs->nShapeId;
3153 bool CompareSvxMSDffShapeInfoByTxBxComp::operator() (
3154 std::shared_ptr<SvxMSDffShapeInfo> const& lhs,
3155 std::shared_ptr<SvxMSDffShapeInfo> const& rhs) const
3157 return lhs->nTxBxComp < rhs->nTxBxComp;
3160 void SvxMSDffManager::Scale( sal_Int32& rVal ) const
3162 if ( bNeedMap )
3164 if (rVal > nMaxAllowedVal)
3166 SAL_WARN("filter.ms", "Cannot scale value: " << rVal);
3167 rVal = SAL_MAX_INT32;
3168 return;
3170 else if (rVal < nMinAllowedVal)
3172 SAL_WARN("filter.ms", "Cannot scale value: " << rVal);
3173 rVal = SAL_MAX_INT32;
3174 return;
3177 rVal = BigMulDiv( rVal, nMapMul, nMapDiv );
3181 void SvxMSDffManager::Scale( Point& rPos ) const
3183 rPos.AdjustX(nMapXOfs );
3184 rPos.AdjustY(nMapYOfs );
3185 if ( bNeedMap )
3187 rPos.setX( BigMulDiv( rPos.X(), nMapMul, nMapDiv ) );
3188 rPos.setY( BigMulDiv( rPos.Y(), nMapMul, nMapDiv ) );
3192 void SvxMSDffManager::Scale( Size& rSiz ) const
3194 if ( bNeedMap )
3196 rSiz.setWidth( BigMulDiv( rSiz.Width(), nMapMul, nMapDiv ) );
3197 rSiz.setHeight( BigMulDiv( rSiz.Height(), nMapMul, nMapDiv ) );
3201 void SvxMSDffManager::ScaleEmu( sal_Int32& rVal ) const
3203 rVal = BigMulDiv( rVal, nEmuMul, nEmuDiv );
3206 sal_uInt32 SvxMSDffManager::ScalePt( sal_uInt32 nVal ) const
3208 MapUnit eMap = pSdrModel->GetScaleUnit();
3209 Fraction aFact( GetMapFactor( MapUnit::MapPoint, eMap ).X() );
3210 tools::Long aMul = aFact.GetNumerator();
3211 tools::Long aDiv = aFact.GetDenominator() * 65536;
3212 aFact = Fraction( aMul, aDiv ); // try again to shorten it
3213 return BigMulDiv( nVal, aFact.GetNumerator(), aFact.GetDenominator() );
3216 sal_Int32 SvxMSDffManager::ScalePoint( sal_Int32 nVal ) const
3218 return BigMulDiv( nVal, nPntMul, nPntDiv );
3221 void SvxMSDffManager::SetModel(SdrModel* pModel, tools::Long nApplicationScale)
3223 pSdrModel = pModel;
3224 if( pModel && (0 < nApplicationScale) )
3226 // PPT works in units of 576DPI
3227 // WW on the other side uses twips, i.e. 1440DPI.
3228 MapUnit eMap = pSdrModel->GetScaleUnit();
3229 Fraction aFact( GetMapFactor(MapUnit::MapInch, eMap).X() );
3230 tools::Long nMul=aFact.GetNumerator();
3231 tools::Long nDiv=aFact.GetDenominator()*nApplicationScale;
3232 aFact=Fraction(nMul,nDiv); // try again to shorten it
3233 // For 100TH_MM -> 2540/576=635/144
3234 // For Twip -> 1440/576=5/2
3235 nMapMul = aFact.GetNumerator();
3236 nMapDiv = aFact.GetDenominator();
3237 bNeedMap = nMapMul!=nMapDiv;
3239 // MS-DFF-Properties are mostly given in EMU (English Metric Units)
3240 // 1mm=36000emu, 1twip=635emu
3241 aFact=GetMapFactor(MapUnit::Map100thMM,eMap).X();
3242 nMul=aFact.GetNumerator();
3243 nDiv=aFact.GetDenominator()*360;
3244 aFact=Fraction(nMul,nDiv); // try again to shorten it
3245 // For 100TH_MM -> 1/360
3246 // For Twip -> 14,40/(25,4*360)=144/91440=1/635
3247 nEmuMul=aFact.GetNumerator();
3248 nEmuDiv=aFact.GetDenominator();
3250 // And something for typographic Points
3251 aFact=GetMapFactor(MapUnit::MapPoint,eMap).X();
3252 nPntMul=aFact.GetNumerator();
3253 nPntDiv=aFact.GetDenominator();
3255 else
3257 pModel = nullptr;
3258 nMapMul = nMapDiv = nMapXOfs = nMapYOfs = nEmuMul = nEmuDiv = nPntMul = nPntDiv = 0;
3259 bNeedMap = false;
3262 if (bNeedMap)
3264 assert(nMapMul > nMapDiv);
3266 BigInt aMinVal(SAL_MIN_INT32);
3267 aMinVal /= nMapMul;
3268 aMinVal *= nMapDiv;
3269 nMinAllowedVal = aMinVal;
3271 BigInt aMaxVal(SAL_MAX_INT32);
3272 aMaxVal /= nMapMul;
3273 aMaxVal *= nMapDiv;
3274 nMaxAllowedVal = aMaxVal;
3276 else
3278 nMinAllowedVal = SAL_MIN_INT32;
3279 nMaxAllowedVal = SAL_MAX_INT32;
3283 bool SvxMSDffManager::SeekToShape( SvStream& rSt, SvxMSDffClientData* /* pClientData */, sal_uInt32 nId ) const
3285 bool bRet = false;
3286 if ( !maFidcls.empty() )
3288 sal_uInt64 nOldPos = rSt.Tell();
3289 sal_uInt32 nSec = ( nId >> 10 ) - 1;
3290 if ( nSec < mnIdClusters )
3292 OffsetMap::const_iterator it = maDgOffsetTable.find( maFidcls[ nSec ].dgid );
3293 if ( it != maDgOffsetTable.end() )
3295 sal_uInt64 nOfs = it->second;
3296 rSt.Seek( nOfs );
3297 DffRecordHeader aEscherF002Hd;
3298 bool bOk = ReadDffRecordHeader( rSt, aEscherF002Hd );
3299 sal_uLong nEscherF002End = bOk ? aEscherF002Hd.GetRecEndFilePos() : 0;
3300 while (rSt.good() && rSt.Tell() < nEscherF002End)
3302 DffRecordHeader aEscherObjListHd;
3303 if (!ReadDffRecordHeader(rSt, aEscherObjListHd))
3304 break;
3305 if ( aEscherObjListHd.nRecVer != 0xf )
3307 bool bSeekSuccess = aEscherObjListHd.SeekToEndOfRecord(rSt);
3308 if (!bSeekSuccess)
3309 break;
3311 else if ( aEscherObjListHd.nRecType == DFF_msofbtSpContainer )
3313 DffRecordHeader aShapeHd;
3314 if ( SeekToRec( rSt, DFF_msofbtSp, aEscherObjListHd.GetRecEndFilePos(), &aShapeHd ) )
3316 sal_uInt32 nShapeId(0);
3317 rSt.ReadUInt32( nShapeId );
3318 if ( nId == nShapeId )
3320 aEscherObjListHd.SeekToBegOfRecord( rSt );
3321 bRet = true;
3322 break;
3325 bool bSeekSuccess = aEscherObjListHd.SeekToEndOfRecord(rSt);
3326 if (!bSeekSuccess)
3327 break;
3332 if ( !bRet )
3333 rSt.Seek( nOldPos );
3335 return bRet;
3338 bool SvxMSDffManager::SeekToRec( SvStream& rSt, sal_uInt16 nRecId, sal_uLong nMaxFilePos, DffRecordHeader* pRecHd, sal_uLong nSkipCount )
3340 bool bRet = false;
3341 sal_uInt64 nOldFPos = rSt.Tell(); // store FilePos to restore it later if necessary
3344 DffRecordHeader aHd;
3345 if (!ReadDffRecordHeader(rSt, aHd))
3346 break;
3347 if (aHd.nRecLen > nMaxLegalDffRecordLength)
3348 break;
3349 if ( aHd.nRecType == nRecId )
3351 if ( nSkipCount )
3352 nSkipCount--;
3353 else
3355 bRet = true;
3356 if ( pRecHd != nullptr )
3357 *pRecHd = aHd;
3358 else
3360 bool bSeekSuccess = aHd.SeekToBegOfRecord(rSt);
3361 if (!bSeekSuccess)
3363 bRet = false;
3364 break;
3369 if ( !bRet )
3371 bool bSeekSuccess = aHd.SeekToEndOfRecord(rSt);
3372 if (!bSeekSuccess)
3373 break;
3376 while ( rSt.good() && rSt.Tell() < nMaxFilePos && !bRet );
3377 if ( !bRet )
3378 rSt.Seek( nOldFPos ); // restore original FilePos
3379 return bRet;
3382 bool SvxMSDffManager::SeekToRec2( sal_uInt16 nRecId1, sal_uInt16 nRecId2, sal_uLong nMaxFilePos ) const
3384 bool bRet = false;
3385 sal_uInt64 nOldFPos = rStCtrl.Tell(); // remember FilePos for conditionally later restoration
3388 DffRecordHeader aHd;
3389 if (!ReadDffRecordHeader(rStCtrl, aHd))
3390 break;
3391 if ( aHd.nRecType == nRecId1 || aHd.nRecType == nRecId2 )
3393 bRet = true;
3394 bool bSeekSuccess = aHd.SeekToBegOfRecord(rStCtrl);
3395 if (!bSeekSuccess)
3397 bRet = false;
3398 break;
3401 if ( !bRet )
3403 bool bSeekSuccess = aHd.SeekToEndOfRecord(rStCtrl);
3404 if (!bSeekSuccess)
3405 break;
3408 while ( rStCtrl.good() && rStCtrl.Tell() < nMaxFilePos && !bRet );
3409 if ( !bRet )
3410 rStCtrl.Seek( nOldFPos ); // restore FilePos
3411 return bRet;
3415 bool SvxMSDffManager::GetColorFromPalette( sal_uInt16 /* nNum */, Color& rColor ) const
3417 // This method has to be overwritten in the class
3418 // derived for the excel export
3419 rColor = COL_WHITE;
3420 return true;
3423 // sj: the documentation is not complete, especially in ppt the normal rgb for text
3424 // color is written as 0xfeRRGGBB, this can't be explained by the documentation, nearly
3425 // every bit in the upper code is set -> so there seems to be a special handling for
3426 // ppt text colors, i decided not to fix this in MSO_CLR_ToColor because of possible
3427 // side effects, instead MSO_TEXT_CLR_ToColor is called for PPT text colors, to map
3428 // the color code to something that behaves like the other standard color codes used by
3429 // fill and line color
3430 Color SvxMSDffManager::MSO_TEXT_CLR_ToColor( sal_uInt32 nColorCode ) const
3432 // for text colors: Header is 0xfeRRGGBB
3433 if ( ( nColorCode & 0xfe000000 ) == 0xfe000000 )
3434 nColorCode &= 0x00ffffff;
3435 else
3437 // for colorscheme colors the color index are the lower three bits of the upper byte
3438 if ( ( nColorCode & 0xf8000000 ) == 0 ) // this must be a colorscheme index
3440 nColorCode >>= 24;
3441 nColorCode |= 0x8000000;
3444 return MSO_CLR_ToColor( nColorCode );
3447 Color SvxMSDffManager::MSO_CLR_ToColor( sal_uInt32 nColorCode, sal_uInt16 nContentProperty ) const
3449 Color aColor( mnDefaultColor );
3451 // for text colors: Header is 0xfeRRGGBB
3452 if ( ( nColorCode & 0xfe000000 ) == 0xfe000000 ) // sj: it needs to be checked if 0xfe is used in
3453 nColorCode &= 0x00ffffff; // other cases than ppt text -> if not this code can be removed
3455 sal_uInt8 nUpper = static_cast<sal_uInt8>( nColorCode >> 24 );
3457 // sj: below change from 0x1b to 0x19 was done because of i84812 (0x02 -> rgb color),
3458 // now I have some problems to fix i104685 (there the color value is 0x02000000 which requires
3459 // a 0x2 scheme color to be displayed properly), the color docu seems to be incomplete
3460 if( nUpper & 0x19 ) // if( nUpper & 0x1f )
3462 if( ( nUpper & 0x08 ) || ( ( nUpper & 0x10 ) == 0 ) )
3464 // SCHEMECOLOR
3465 if ( !GetColorFromPalette( ( nUpper & 8 ) ? static_cast<sal_uInt16>(nColorCode) : nUpper, aColor ) )
3467 switch( nContentProperty )
3469 case DFF_Prop_pictureTransparent :
3470 case DFF_Prop_shadowColor :
3471 case DFF_Prop_fillBackColor :
3472 case DFF_Prop_fillColor :
3473 aColor = COL_WHITE;
3474 break;
3475 case DFF_Prop_lineColor :
3477 aColor = COL_BLACK;
3479 break;
3483 else // SYSCOLOR
3485 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
3487 sal_uInt16 nParameter = sal_uInt16(( nColorCode >> 16 ) & 0x00ff); // the HiByte of nParameter is not zero, an exclusive AND is helping :o
3488 sal_uInt16 nFunctionBits = static_cast<sal_uInt16>( ( nColorCode & 0x00000f00 ) >> 8 );
3489 sal_uInt16 nAdditionalFlags = static_cast<sal_uInt16>( ( nColorCode & 0x0000f000) >> 8 );
3490 sal_uInt16 nColorIndex = sal_uInt16(nColorCode & 0x00ff);
3491 sal_uInt32 nPropColor = 0;
3493 sal_uInt16 nCProp = 0;
3495 switch ( nColorIndex )
3497 case mso_syscolorButtonFace : aColor = rStyleSettings.GetFaceColor(); break;
3498 case mso_syscolorWindowText : aColor = rStyleSettings.GetWindowTextColor(); break;
3499 case mso_syscolorMenu : aColor = rStyleSettings.GetMenuColor(); break;
3500 case mso_syscolor3DLight :
3501 case mso_syscolorButtonHighlight :
3502 case mso_syscolorHighlight : aColor = rStyleSettings.GetHighlightColor(); break;
3503 case mso_syscolorHighlightText : aColor = rStyleSettings.GetHighlightTextColor(); break;
3504 case mso_syscolorCaptionText : aColor = rStyleSettings.GetMenuTextColor(); break;
3505 case mso_syscolorActiveCaption : aColor = rStyleSettings.GetHighlightColor(); break;
3506 case mso_syscolorButtonShadow : aColor = rStyleSettings.GetShadowColor(); break;
3507 case mso_syscolorButtonText : aColor = rStyleSettings.GetButtonTextColor(); break;
3508 case mso_syscolorGrayText : aColor = rStyleSettings.GetDeactiveColor(); break;
3509 case mso_syscolorInactiveCaption : aColor = rStyleSettings.GetDeactiveColor(); break;
3510 case mso_syscolorInactiveCaptionText : aColor = rStyleSettings.GetDeactiveColor(); break;
3511 case mso_syscolorInfoBackground : aColor = rStyleSettings.GetFaceColor(); break;
3512 case mso_syscolorInfoText : aColor = rStyleSettings.GetLabelTextColor(); break;
3513 case mso_syscolorMenuText : aColor = rStyleSettings.GetMenuTextColor(); break;
3514 case mso_syscolorScrollbar : aColor = rStyleSettings.GetFaceColor(); break;
3515 case mso_syscolorWindow : aColor = rStyleSettings.GetWindowColor(); break;
3516 case mso_syscolorWindowFrame : aColor = rStyleSettings.GetWindowColor(); break;
3518 case mso_colorFillColor :
3520 nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff );
3521 nCProp = DFF_Prop_fillColor;
3523 break;
3524 case mso_colorLineOrFillColor : // ( use the line color only if there is a line )
3526 if ( GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 ) & 8 )
3528 nPropColor = GetPropertyValue( DFF_Prop_lineColor, 0 );
3529 nCProp = DFF_Prop_lineColor;
3531 else
3533 nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff );
3534 nCProp = DFF_Prop_fillColor;
3537 break;
3538 case mso_colorLineColor :
3540 nPropColor = GetPropertyValue( DFF_Prop_lineColor, 0 );
3541 nCProp = DFF_Prop_lineColor;
3543 break;
3544 case mso_colorShadowColor :
3546 nPropColor = GetPropertyValue( DFF_Prop_shadowColor, 0x808080 );
3547 nCProp = DFF_Prop_shadowColor;
3549 break;
3550 case mso_colorThis : // ( use this color ... )
3552 nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff ); //?????????????
3553 nCProp = DFF_Prop_fillColor;
3555 break;
3556 case mso_colorFillBackColor :
3558 nPropColor = GetPropertyValue( DFF_Prop_fillBackColor, 0xffffff );
3559 nCProp = DFF_Prop_fillBackColor;
3561 break;
3562 case mso_colorLineBackColor :
3564 nPropColor = GetPropertyValue( DFF_Prop_lineBackColor, 0xffffff );
3565 nCProp = DFF_Prop_lineBackColor;
3567 break;
3568 case mso_colorFillThenLine : // ( use the fillcolor unless no fill and line )
3570 nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff ); //?????????????
3571 nCProp = DFF_Prop_fillColor;
3573 break;
3574 case mso_colorIndexMask : // ( extract the color index ) ?
3576 nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff ); //?????????????
3577 nCProp = DFF_Prop_fillColor;
3579 break;
3581 if ( nCProp && ( nPropColor & 0x10000000 ) == 0 ) // beware of looping recursive
3582 aColor = MSO_CLR_ToColor( nPropColor, nCProp );
3584 if( nAdditionalFlags & 0x80 ) // make color gray
3586 sal_uInt8 nZwi = aColor.GetLuminance();
3587 aColor = Color( nZwi, nZwi, nZwi );
3589 switch( nFunctionBits )
3591 case 0x01 : // darken color by parameter
3593 aColor.SetRed( sal::static_int_cast< sal_uInt8 >( ( nParameter * aColor.GetRed() ) >> 8 ) );
3594 aColor.SetGreen( sal::static_int_cast< sal_uInt8 >( ( nParameter * aColor.GetGreen() ) >> 8 ) );
3595 aColor.SetBlue( sal::static_int_cast< sal_uInt8 >( ( nParameter * aColor.GetBlue() ) >> 8 ) );
3597 break;
3598 case 0x02 : // lighten color by parameter
3600 sal_uInt16 nInvParameter = ( 0x00ff - nParameter ) * 0xff;
3601 aColor.SetRed( sal::static_int_cast< sal_uInt8 >( ( nInvParameter + ( nParameter * aColor.GetRed() ) ) >> 8 ) );
3602 aColor.SetGreen( sal::static_int_cast< sal_uInt8 >( ( nInvParameter + ( nParameter * aColor.GetGreen() ) ) >> 8 ) );
3603 aColor.SetBlue( sal::static_int_cast< sal_uInt8 >( ( nInvParameter + ( nParameter * aColor.GetBlue() ) ) >> 8 ) );
3605 break;
3606 case 0x03 : // add grey level RGB(p,p,p)
3608 sal_Int16 nR = static_cast<sal_Int16>(aColor.GetRed()) + static_cast<sal_Int16>(nParameter);
3609 sal_Int16 nG = static_cast<sal_Int16>(aColor.GetGreen()) + static_cast<sal_Int16>(nParameter);
3610 sal_Int16 nB = static_cast<sal_Int16>(aColor.GetBlue()) + static_cast<sal_Int16>(nParameter);
3611 if ( nR > 0x00ff )
3612 nR = 0x00ff;
3613 if ( nG > 0x00ff )
3614 nG = 0x00ff;
3615 if ( nB > 0x00ff )
3616 nB = 0x00ff;
3617 aColor = Color( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
3619 break;
3620 case 0x04 : // subtract grey level RGB(p,p,p)
3622 sal_Int16 nR = static_cast<sal_Int16>(aColor.GetRed()) - static_cast<sal_Int16>(nParameter);
3623 sal_Int16 nG = static_cast<sal_Int16>(aColor.GetGreen()) - static_cast<sal_Int16>(nParameter);
3624 sal_Int16 nB = static_cast<sal_Int16>(aColor.GetBlue()) - static_cast<sal_Int16>(nParameter);
3625 if ( nR < 0 )
3626 nR = 0;
3627 if ( nG < 0 )
3628 nG = 0;
3629 if ( nB < 0 )
3630 nB = 0;
3631 aColor = Color( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
3633 break;
3634 case 0x05 : // subtract from gray level RGB(p,p,p)
3636 sal_Int16 nR = static_cast<sal_Int16>(nParameter) - static_cast<sal_Int16>(aColor.GetRed());
3637 sal_Int16 nG = static_cast<sal_Int16>(nParameter) - static_cast<sal_Int16>(aColor.GetGreen());
3638 sal_Int16 nB = static_cast<sal_Int16>(nParameter) - static_cast<sal_Int16>(aColor.GetBlue());
3639 if ( nR < 0 )
3640 nR = 0;
3641 if ( nG < 0 )
3642 nG = 0;
3643 if ( nB < 0 )
3644 nB = 0;
3645 aColor = Color( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
3647 break;
3648 case 0x06 : // per component: black if < p, white if >= p
3650 aColor.SetRed( aColor.GetRed() < nParameter ? 0x00 : 0xff );
3651 aColor.SetGreen( aColor.GetGreen() < nParameter ? 0x00 : 0xff );
3652 aColor.SetBlue( aColor.GetBlue() < nParameter ? 0x00 : 0xff );
3654 break;
3656 if ( nAdditionalFlags & 0x40 ) // top-bit invert
3657 aColor = Color( aColor.GetRed() ^ 0x80, aColor.GetGreen() ^ 0x80, aColor.GetBlue() ^ 0x80 );
3659 if ( nAdditionalFlags & 0x20 ) // invert color
3660 aColor = Color(0xff - aColor.GetRed(), 0xff - aColor.GetGreen(), 0xff - aColor.GetBlue());
3663 else if ( ( nUpper & 4 ) && ( ( nColorCode & 0xfffff8 ) == 0 ) )
3664 { // case of nUpper == 4 powerpoint takes this as argument for a colorschemecolor
3665 GetColorFromPalette( nUpper, aColor );
3667 else // attributed hard, maybe with hint to SYSTEMRGB
3668 aColor = Color( static_cast<sal_uInt8>(nColorCode), static_cast<sal_uInt8>( nColorCode >> 8 ), static_cast<sal_uInt8>( nColorCode >> 16 ) );
3669 return aColor;
3672 void SvxMSDffManager::ReadObjText( SvStream& rStream, SdrObject* pObj )
3674 DffRecordHeader aRecHd;
3675 if (!ReadDffRecordHeader(rStream, aRecHd))
3676 return;
3677 if( aRecHd.nRecType != DFF_msofbtClientTextbox && aRecHd.nRecType != 0x1022 )
3678 return;
3680 while (rStream.good() && rStream.Tell() < aRecHd.GetRecEndFilePos())
3682 DffRecordHeader aHd;
3683 if (!ReadDffRecordHeader(rStream, aHd))
3684 break;
3685 switch( aHd.nRecType )
3687 case DFF_PST_TextBytesAtom:
3688 case DFF_PST_TextCharsAtom:
3690 bool bUniCode = ( aHd.nRecType == DFF_PST_TextCharsAtom );
3691 sal_uInt32 nBytes = aHd.nRecLen;
3692 OUString aStr = MSDFFReadZString( rStream, nBytes, bUniCode );
3693 ReadObjText( aStr, pObj );
3695 break;
3696 default:
3697 break;
3699 bool bSeekSuccess = aHd.SeekToEndOfRecord(rStream);
3700 if (!bSeekSuccess)
3701 break;
3705 // sj: I just want to set a string for a text object that may contain multiple
3706 // paragraphs. If I now take a look at the following code I get the impression that
3707 // our outliner is too complicate to be used properly,
3708 void SvxMSDffManager::ReadObjText( const OUString& rText, SdrObject* pObj )
3710 SdrTextObj* pText = DynCastSdrTextObj( pObj );
3711 if ( !pText )
3712 return;
3714 SdrOutliner& rOutliner = pText->ImpGetDrawOutliner();
3715 rOutliner.Init( OutlinerMode::TextObject );
3717 bool bOldUpdateMode = rOutliner.SetUpdateLayout( false );
3718 rOutliner.SetVertical( pText->IsVerticalWriting() );
3720 sal_Int32 nParaIndex = 0;
3721 sal_Int32 nParaSize;
3722 const sal_Unicode* pBuf = rText.getStr();
3723 const sal_Unicode* pEnd = rText.getStr() + rText.getLength();
3725 while( pBuf < pEnd )
3727 const sal_Unicode* pCurrent = pBuf;
3729 for ( nParaSize = 0; pBuf < pEnd; )
3731 sal_Unicode nChar = *pBuf++;
3732 if ( nChar == 0xa )
3734 if ( ( pBuf < pEnd ) && ( *pBuf == 0xd ) )
3735 pBuf++;
3736 break;
3738 else if ( nChar == 0xd )
3740 if ( ( pBuf < pEnd ) && ( *pBuf == 0xa ) )
3741 pBuf++;
3742 break;
3744 else
3745 ++nParaSize;
3747 ESelection aSelection(nParaIndex, 0);
3748 OUString aParagraph( pCurrent, nParaSize );
3749 if ( !nParaIndex && aParagraph.isEmpty() ) // SJ: we are crashing if the first paragraph is empty ?
3750 aParagraph += " "; // otherwise these two lines can be removed.
3751 rOutliner.Insert( aParagraph, nParaIndex );
3752 rOutliner.SetParaAttribs( nParaIndex, rOutliner.GetEmptyItemSet() );
3754 SfxItemSet aParagraphAttribs( rOutliner.GetEmptyItemSet() );
3755 if (!aSelection.start.nIndex)
3756 aParagraphAttribs.Put( SfxBoolItem( EE_PARA_BULLETSTATE, false ) );
3757 aSelection.start.nIndex = 0;
3758 rOutliner.QuickSetAttribs( aParagraphAttribs, aSelection );
3759 nParaIndex++;
3761 std::optional<OutlinerParaObject> pNewText = rOutliner.CreateParaObject();
3762 rOutliner.Clear();
3763 rOutliner.SetUpdateLayout( bOldUpdateMode );
3764 pText->SetOutlinerParaObject( std::move(pNewText) );
3765 // tdf#143315: restore stylesheet applied to Outliner's nodes when SdrTextObj initializes
3766 // its attributes, but removed by Outliner::Init, which calls Outliner::Clear.
3767 pText->SetStyleSheet(pText->GetStyleSheet(), true);
3770 //static
3771 OUString SvxMSDffManager::MSDFFReadZString(SvStream& rIn,
3772 sal_uInt32 nLen, bool bUniCode)
3774 if (!nLen)
3775 return OUString();
3777 OUString sBuf;
3779 if( bUniCode )
3780 sBuf = read_uInt16s_ToOUString(rIn, nLen/2);
3781 else
3782 sBuf = read_uInt8s_ToOUString(rIn, nLen, RTL_TEXTENCODING_MS_1252);
3784 return comphelper::string::stripEnd(sBuf, 0);
3787 static Size lcl_GetPrefSize(const Graphic& rGraf, const MapMode& aWanted)
3789 MapMode aPrefMapMode(rGraf.GetPrefMapMode());
3790 if (aPrefMapMode == aWanted)
3791 return rGraf.GetPrefSize();
3792 Size aRetSize;
3793 if (aPrefMapMode.GetMapUnit() == MapUnit::MapPixel)
3795 aRetSize = Application::GetDefaultDevice()->PixelToLogic(
3796 rGraf.GetPrefSize(), aWanted);
3798 else
3800 aRetSize = OutputDevice::LogicToLogic(
3801 rGraf.GetPrefSize(), rGraf.GetPrefMapMode(), aWanted);
3803 return aRetSize;
3806 // sj: if the parameter pSet is null, then the resulting crop bitmap will be stored in rGraf,
3807 // otherwise rGraf is untouched and pSet is used to store the corresponding SdrGrafCropItem
3808 static void lcl_ApplyCropping( const DffPropSet& rPropSet, SfxItemSet* pSet, Graphic& rGraf )
3810 sal_Int32 nCropTop = static_cast<sal_Int32>(rPropSet.GetPropertyValue( DFF_Prop_cropFromTop, 0 ));
3811 sal_Int32 nCropBottom = static_cast<sal_Int32>(rPropSet.GetPropertyValue( DFF_Prop_cropFromBottom, 0 ));
3812 sal_Int32 nCropLeft = static_cast<sal_Int32>(rPropSet.GetPropertyValue( DFF_Prop_cropFromLeft, 0 ));
3813 sal_Int32 nCropRight = static_cast<sal_Int32>(rPropSet.GetPropertyValue( DFF_Prop_cropFromRight, 0 ));
3815 if( !(nCropTop || nCropBottom || nCropLeft || nCropRight) )
3816 return;
3818 double fFactor;
3819 Size aCropSize;
3820 BitmapEx aCropBitmap;
3821 sal_uInt32 nTop( 0 ), nBottom( 0 ), nLeft( 0 ), nRight( 0 );
3823 // Cropping has to be applied on a loaded graphic.
3824 rGraf.makeAvailable();
3826 if ( pSet ) // use crop attributes ?
3827 aCropSize = lcl_GetPrefSize(rGraf, MapMode(MapUnit::Map100thMM));
3828 else
3830 aCropBitmap = rGraf.GetBitmapEx();
3831 aCropSize = aCropBitmap.GetSizePixel();
3833 if ( nCropTop )
3835 fFactor = static_cast<double>(nCropTop) / 65536.0;
3836 nTop = static_cast<sal_uInt32>( ( static_cast<double>( aCropSize.Height() + 1 ) * fFactor ) + 0.5 );
3838 if ( nCropBottom )
3840 fFactor = static_cast<double>(nCropBottom) / 65536.0;
3841 nBottom = static_cast<sal_uInt32>( ( static_cast<double>( aCropSize.Height() + 1 ) * fFactor ) + 0.5 );
3843 if ( nCropLeft )
3845 fFactor = static_cast<double>(nCropLeft) / 65536.0;
3846 nLeft = static_cast<sal_uInt32>( ( static_cast<double>( aCropSize.Width() + 1 ) * fFactor ) + 0.5 );
3848 if ( nCropRight )
3850 fFactor = static_cast<double>(nCropRight) / 65536.0;
3851 nRight = static_cast<sal_uInt32>( ( static_cast<double>( aCropSize.Width() + 1 ) * fFactor ) + 0.5 );
3853 if ( pSet ) // use crop attributes ?
3854 pSet->Put( SdrGrafCropItem( nLeft, nTop, nRight, nBottom ) );
3855 else
3857 tools::Rectangle aCropRect( nLeft, nTop, aCropSize.Width() - nRight, aCropSize.Height() - nBottom );
3858 aCropBitmap.Crop( aCropRect );
3859 rGraf = aCropBitmap;
3863 rtl::Reference<SdrObject> SvxMSDffManager::ImportGraphic( SvStream& rSt, SfxItemSet& rSet, const DffObjData& rObjData )
3865 rtl::Reference<SdrObject> pRet;
3866 OUString aLinkFileName;
3867 tools::Rectangle aVisArea;
3869 auto eFlags = GetPropertyValue(DFF_Prop_pibFlags, mso_blipflagDefault);
3870 sal_uInt32 nBlipId = GetPropertyValue( DFF_Prop_pib, 0 );
3871 bool bGrfRead = false,
3873 // Graphic linked
3874 bLinkGrf = 0 != ( eFlags & mso_blipflagLinkToFile );
3876 OUString aFileName;
3877 Graphic aGraf; // be sure this graphic is deleted before swapping out
3878 if( SeekToContent( DFF_Prop_pibName, rSt ) )
3879 aFileName = MSDFFReadZString( rSt, GetPropertyValue( DFF_Prop_pibName, 0 ), true );
3881 // AND, OR the following:
3882 if( !( eFlags & mso_blipflagDoNotSave ) ) // Graphic embedded
3884 bGrfRead = GetBLIP( nBlipId, aGraf, &aVisArea );
3885 if ( !bGrfRead )
3888 Still no luck, let's look at the end of this record for a FBSE pool,
3889 this fallback is a specific case for how word does it sometimes
3891 bool bOk = rObjData.rSpHd.SeekToEndOfRecord( rSt );
3892 DffRecordHeader aHd;
3893 if (bOk)
3895 bOk = ReadDffRecordHeader(rSt, aHd);
3897 if (bOk && DFF_msofbtBSE == aHd.nRecType)
3899 const sal_uInt8 nSkipBLIPLen = 20;
3900 const sal_uInt8 nSkipShapePos = 4;
3901 const sal_uInt8 nSkipBLIP = 4;
3902 const sal_uLong nSkip =
3903 nSkipBLIPLen + 4 + nSkipShapePos + 4 + nSkipBLIP;
3905 if (nSkip <= aHd.nRecLen)
3907 rSt.SeekRel(nSkip);
3908 if (ERRCODE_NONE == rSt.GetError())
3909 bGrfRead = GetBLIPDirect( rSt, aGraf, &aVisArea );
3914 if ( bGrfRead )
3916 // the writer is doing its own cropping, so this part affects only impress and calc,
3917 // unless we're inside a group, in which case writer doesn't crop either
3918 if (( GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_CROP_BITMAPS ) || rObjData.nCalledByGroup != 0 )
3919 lcl_ApplyCropping( *this, !bool( rObjData.nSpFlags & ShapeFlag::OLEShape ) ? &rSet : nullptr, aGraf );
3921 if ( IsProperty( DFF_Prop_pictureTransparent ) )
3923 sal_uInt32 nTransColor = GetPropertyValue( DFF_Prop_pictureTransparent, 0 );
3925 if ( aGraf.GetType() == GraphicType::Bitmap )
3927 BitmapEx aBitmapEx( aGraf.GetBitmapEx() );
3928 aBitmapEx.CombineMaskOr( MSO_CLR_ToColor( nTransColor, DFF_Prop_pictureTransparent ), 9 );
3929 aGraf = aBitmapEx;
3933 sal_Int32 nContrast = GetPropertyValue( DFF_Prop_pictureContrast, 0x10000 );
3935 0x10000 is msoffice 50%
3936 < 0x10000 is in units of 1/50th of 0x10000 per 1%
3937 > 0x10000 is in units where
3938 a msoffice x% is stored as 50/(100-x) * 0x10000
3940 plus, a (ui) microsoft % ranges from 0 to 100, OOO
3941 from -100 to 100, so also normalize into that range
3943 if ( nContrast > 0x10000 )
3945 double fX = nContrast;
3946 fX /= 0x10000;
3947 fX /= 51; // 50 + 1 to round
3948 fX = 1/fX;
3949 nContrast = static_cast<sal_Int32>(fX);
3950 nContrast -= 100;
3951 nContrast = -nContrast;
3952 nContrast = (nContrast-50)*2;
3954 else if ( nContrast == 0x10000 )
3955 nContrast = 0;
3956 else
3958 if (o3tl::checked_multiply<sal_Int32>(nContrast, 101, nContrast)) //100 + 1 to round
3960 SAL_WARN("filter.ms", "bad Contrast value:" << nContrast);
3961 nContrast = 0;
3963 else
3965 nContrast /= 0x10000;
3966 nContrast -= 100;
3969 sal_Int16 nBrightness = static_cast<sal_Int16>( static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_pictureBrightness, 0 )) / 327 );
3970 sal_Int32 nGamma = GetPropertyValue( DFF_Prop_pictureGamma, 0x10000 );
3971 GraphicDrawMode eDrawMode = GraphicDrawMode::Standard;
3972 switch ( GetPropertyValue( DFF_Prop_pictureActive, 0 ) & 6 )
3974 case 4 : eDrawMode = GraphicDrawMode::Greys; break;
3975 case 6 : eDrawMode = GraphicDrawMode::Mono; break;
3976 case 0 :
3978 //office considers the converted values of (in OOo) 70 to be the
3979 //"watermark" values, which can vary slightly due to rounding from the
3980 //above values
3981 if (( nContrast == -70 ) && ( nBrightness == 70 ))
3983 nContrast = 0;
3984 nBrightness = 0;
3985 eDrawMode = GraphicDrawMode::Watermark;
3988 break;
3991 if ( nContrast || nBrightness || ( nGamma != 0x10000 ) || ( eDrawMode != GraphicDrawMode::Standard ) )
3993 // MSO uses a different algorithm for contrast+brightness, LO applies contrast before brightness,
3994 // while MSO apparently applies half of brightness before contrast and half after. So if only
3995 // contrast or brightness need to be altered, the result is the same, but if both are involved,
3996 // there's no way to map that, so just force a conversion of the image.
3997 bool needsConversion = nContrast != 0 && nBrightness != 0;
3998 if ( !bool(rObjData.nSpFlags & ShapeFlag::OLEShape) && !needsConversion )
4000 if ( nBrightness )
4001 rSet.Put( SdrGrafLuminanceItem( nBrightness ) );
4002 if ( nContrast )
4003 rSet.Put( SdrGrafContrastItem( static_cast<sal_Int16>(nContrast) ) );
4004 if ( nGamma != 0x10000 )
4005 rSet.Put( SdrGrafGamma100Item( nGamma / 655 ) );
4006 if ( eDrawMode != GraphicDrawMode::Standard )
4007 rSet.Put( SdrGrafModeItem( eDrawMode ) );
4009 else
4011 if ( eDrawMode == GraphicDrawMode::Watermark )
4013 nContrast = 60;
4014 nBrightness = 70;
4015 eDrawMode = GraphicDrawMode::Standard;
4017 switch ( aGraf.GetType() )
4019 case GraphicType::Bitmap :
4021 BitmapEx aBitmapEx( aGraf.GetBitmapEx() );
4022 if ( nBrightness || nContrast || ( nGamma != 0x10000 ) )
4023 aBitmapEx.Adjust( nBrightness, static_cast<sal_Int16>(nContrast), 0, 0, 0, static_cast<double>(nGamma) / 0x10000, false, true );
4024 if ( eDrawMode == GraphicDrawMode::Greys )
4025 aBitmapEx.Convert( BmpConversion::N8BitGreys );
4026 else if ( eDrawMode == GraphicDrawMode::Mono )
4027 aBitmapEx.Convert( BmpConversion::N1BitThreshold );
4028 aGraf = aBitmapEx;
4031 break;
4033 case GraphicType::GdiMetafile :
4035 GDIMetaFile aGdiMetaFile( aGraf.GetGDIMetaFile() );
4036 if ( nBrightness || nContrast || ( nGamma != 0x10000 ) )
4037 aGdiMetaFile.Adjust( nBrightness, static_cast<sal_Int16>(nContrast), 0, 0, 0, static_cast<double>(nGamma) / 0x10000, false, true );
4038 if ( eDrawMode == GraphicDrawMode::Greys )
4039 aGdiMetaFile.Convert( MtfConversion::N8BitGreys );
4040 else if ( eDrawMode == GraphicDrawMode::Mono )
4041 aGdiMetaFile.Convert( MtfConversion::N1BitThreshold );
4042 aGraf = aGdiMetaFile;
4044 break;
4045 default: break;
4051 // should it be an OLE object?
4052 if( bGrfRead && !bLinkGrf && IsProperty( DFF_Prop_pictureId ) )
4054 // TODO/LATER: in future probably the correct aspect should be provided here
4055 // #i32596# - pass <nCalledByGroup> to method
4056 pRet = ImportOLE( GetPropertyValue( DFF_Prop_pictureId, 0 ), aGraf, rObjData.aBoundRect, aVisArea, rObjData.nCalledByGroup );
4058 if( !pRet )
4060 pRet = new SdrGrafObj(*pSdrModel);
4061 if( bGrfRead )
4062 static_cast<SdrGrafObj*>(pRet.get())->SetGraphic( aGraf );
4064 if( bLinkGrf && !bGrfRead ) // sj: #i55484# if the graphic was embedded ( bGrfRead == true ) then
4065 { // we do not need to set a link. TODO: not to lose the information where the graphic is linked from
4066 INetURLObject aAbsURL;
4067 if ( !INetURLObject( maBaseURL ).GetNewAbsURL( aFileName, &aAbsURL ) )
4069 OUString aValidURL;
4070 if( osl::FileBase::getFileURLFromSystemPath( aFileName, aValidURL ) == osl::FileBase::E_None )
4071 aAbsURL = INetURLObject( aValidURL );
4073 if( aAbsURL.GetProtocol() != INetProtocol::NotValid )
4075 aLinkFileName = aAbsURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri );
4077 else
4078 aLinkFileName = aFileName;
4082 // set the size from BLIP if there is one
4083 if ( bGrfRead && !aVisArea.IsEmpty() )
4084 pRet->SetBLIPSizeRectangle( aVisArea );
4086 if (pRet->GetName().isEmpty()) // SJ 22.02.00 : PPT OLE IMPORT:
4087 { // name is already set in ImportOLE !!
4088 // JP 01.12.99: SetName before SetModel - because in the other order the Bug 70098 is active
4089 if ( ( eFlags & mso_blipflagType ) != mso_blipflagComment )
4091 INetURLObject aURL;
4092 aURL.SetSmartURL( aFileName );
4093 pRet->SetName( aURL.getBase() );
4095 else
4096 pRet->SetName( aFileName );
4099 pRet->NbcSetLogicRect( rObjData.aBoundRect );
4101 if (SdrGrafObj* pGrafObj = dynamic_cast<SdrGrafObj*>(pRet.get()))
4103 if( aLinkFileName.getLength() )
4105 pGrafObj->SetGraphicLink( aLinkFileName );
4106 Graphic aGraphic(pGrafObj->GetGraphic());
4107 aGraphic.setOriginURL(aLinkFileName);
4110 if ( bLinkGrf && !bGrfRead )
4112 Graphic aGraf(pGrafObj->GetGraphic());
4113 lcl_ApplyCropping( *this, &rSet, aGraf );
4117 return pRet;
4120 // PptSlidePersistEntry& rPersistEntry, SdPage* pPage
4121 rtl::Reference<SdrObject> SvxMSDffManager::ImportObj( SvStream& rSt, SvxMSDffClientData& rClientData,
4122 tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect, int nCalledByGroup, sal_Int32* pShapeId )
4124 rtl::Reference<SdrObject> pRet;
4125 DffRecordHeader aObjHd;
4126 bool bOk = ReadDffRecordHeader(rSt, aObjHd);
4127 if (bOk && aObjHd.nRecType == DFF_msofbtSpgrContainer)
4129 pRet = ImportGroup( aObjHd, rSt, rClientData, rClientRect, rGlobalChildRect, nCalledByGroup, pShapeId );
4131 else if (bOk && aObjHd.nRecType == DFF_msofbtSpContainer)
4133 pRet = ImportShape( aObjHd, rSt, rClientData, rClientRect, rGlobalChildRect, nCalledByGroup, pShapeId );
4135 aObjHd.SeekToBegOfRecord( rSt ); // restore FilePos
4136 return pRet;
4139 rtl::Reference<SdrObject> SvxMSDffManager::ImportGroup( const DffRecordHeader& rHd, SvStream& rSt, SvxMSDffClientData& rClientData,
4140 tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect,
4141 int nCalledByGroup, sal_Int32* pShapeId )
4143 if( pShapeId )
4144 *pShapeId = 0;
4146 if (!rHd.SeekToContent(rSt))
4147 return nullptr;
4149 rtl::Reference<SdrObject> xRet;
4151 DffRecordHeader aRecHd; // the first atom has to be the SpContainer for the GroupObject
4152 bool bOk = ReadDffRecordHeader(rSt, aRecHd);
4153 if (bOk && aRecHd.nRecType == DFF_msofbtSpContainer)
4155 mnFix16Angle = 0_deg100;
4156 if (!aRecHd.SeekToBegOfRecord(rSt))
4157 return xRet;
4158 xRet = ImportObj(rSt, rClientData, rClientRect, rGlobalChildRect, nCalledByGroup + 1, pShapeId);
4159 if (xRet)
4161 Degree100 nGroupRotateAngle(0);
4162 ShapeFlag nSpFlags = nGroupShapeFlags;
4163 nGroupRotateAngle = mnFix16Angle;
4165 tools::Rectangle aClientRect( rClientRect );
4167 tools::Rectangle aGlobalChildRect;
4168 if ( !nCalledByGroup || rGlobalChildRect.IsEmpty() )
4169 aGlobalChildRect = GetGlobalChildAnchor( rHd, rSt, aClientRect );
4170 else
4171 aGlobalChildRect = rGlobalChildRect;
4173 if ( ( nGroupRotateAngle > 4500_deg100 && nGroupRotateAngle <= 13500_deg100 )
4174 || ( nGroupRotateAngle > 22500_deg100 && nGroupRotateAngle <= 31500_deg100 ) )
4176 sal_Int32 nHalfWidth = ( aClientRect.GetWidth() + 1 ) >> 1;
4177 sal_Int32 nHalfHeight = ( aClientRect.GetHeight() + 1 ) >> 1;
4178 Point aTopLeft( aClientRect.Left() + nHalfWidth - nHalfHeight,
4179 aClientRect.Top() + nHalfHeight - nHalfWidth );
4180 const tools::Long nRotatedWidth = aClientRect.GetHeight();
4181 const tools::Long nRotatedHeight = aClientRect.GetWidth();
4182 Size aNewSize(nRotatedWidth, nRotatedHeight);
4183 tools::Rectangle aNewRect( aTopLeft, aNewSize );
4184 aClientRect = aNewRect;
4187 // now importing the inner objects of the group
4188 if (!aRecHd.SeekToEndOfRecord(rSt))
4189 return xRet;
4191 while (rSt.good() && ( rSt.Tell() < rHd.GetRecEndFilePos()))
4193 DffRecordHeader aRecHd2;
4194 if (!ReadDffRecordHeader(rSt, aRecHd2))
4195 break;
4196 if ( aRecHd2.nRecType == DFF_msofbtSpgrContainer )
4198 tools::Rectangle aGroupClientAnchor, aGroupChildAnchor;
4199 GetGroupAnchors( aRecHd2, rSt, aGroupClientAnchor, aGroupChildAnchor, aClientRect, aGlobalChildRect );
4200 if (!aRecHd2.SeekToBegOfRecord(rSt))
4201 return xRet;
4202 sal_Int32 nShapeId;
4203 rtl::Reference<SdrObject> pTmp = ImportGroup( aRecHd2, rSt, rClientData, aGroupClientAnchor, aGroupChildAnchor, nCalledByGroup + 1, &nShapeId );
4204 if (pTmp)
4206 SdrObjGroup* pGroup = dynamic_cast<SdrObjGroup*>(xRet.get());
4207 if (pGroup && pGroup->GetSubList())
4209 pGroup->GetSubList()->NbcInsertObject(pTmp.get());
4210 if (nShapeId)
4211 insertShapeId(nShapeId, pTmp.get());
4213 else
4214 FreeObj(rClientData, pTmp.get());
4217 else if ( aRecHd2.nRecType == DFF_msofbtSpContainer )
4219 if (!aRecHd2.SeekToBegOfRecord(rSt))
4220 return xRet;
4221 sal_Int32 nShapeId;
4222 rtl::Reference<SdrObject> pTmp = ImportShape( aRecHd2, rSt, rClientData, aClientRect, aGlobalChildRect, nCalledByGroup + 1, &nShapeId );
4223 if (pTmp)
4225 SdrObjGroup* pGroup = dynamic_cast<SdrObjGroup*>(xRet.get());
4226 if (pGroup && pGroup->GetSubList())
4228 pGroup->GetSubList()->NbcInsertObject(pTmp.get());
4229 if (nShapeId)
4230 insertShapeId(nShapeId, pTmp.get());
4232 else
4233 FreeObj(rClientData, pTmp.get());
4236 if (!aRecHd2.SeekToEndOfRecord(rSt))
4237 return xRet;
4240 if ( nGroupRotateAngle )
4241 xRet->NbcRotate( aClientRect.Center(), nGroupRotateAngle );
4242 if ( nSpFlags & ShapeFlag::FlipV )
4243 { // BoundRect in aBoundRect
4244 Point aLeft( aClientRect.Left(), ( aClientRect.Top() + aClientRect.Bottom() ) >> 1 );
4245 Point aRight( aLeft.X() + 1000, aLeft.Y() );
4246 xRet->NbcMirror( aLeft, aRight );
4248 if ( nSpFlags & ShapeFlag::FlipH )
4249 { // BoundRect in aBoundRect
4250 Point aTop( ( aClientRect.Left() + aClientRect.Right() ) >> 1, aClientRect.Top() );
4251 Point aBottom( aTop.X(), aTop.Y() + 1000 );
4252 xRet->NbcMirror( aTop, aBottom );
4256 if (o3tl::make_unsigned(nCalledByGroup) < maPendingGroupData.size())
4258 // finalization for this group is pending, do it now
4259 xRet = FinalizeObj(maPendingGroupData.back().first, xRet.get());
4260 maPendingGroupData.pop_back();
4262 return xRet;
4265 rtl::Reference<SdrObject> SvxMSDffManager::ImportShape( const DffRecordHeader& rHd, SvStream& rSt, SvxMSDffClientData& rClientData,
4266 tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect,
4267 int nCalledByGroup, sal_Int32* pShapeId )
4269 if( pShapeId )
4270 *pShapeId = 0;
4272 if (!rHd.SeekToBegOfRecord(rSt))
4273 return nullptr;
4275 DffObjData aObjData( rHd, rClientRect, nCalledByGroup );
4277 aObjData.bRotateTextWithShape = ( GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_EXCEL ) == 0;
4278 maShapeRecords.Consume( rSt );
4279 if( maShapeRecords.SeekToContent( rSt,
4280 DFF_msofbtUDefProp ) )
4282 sal_uInt32 nBytesLeft = maShapeRecords.Current()->nRecLen;
4283 while( 5 < nBytesLeft )
4285 sal_uInt16 nPID(0);
4286 rSt.ReadUInt16(nPID);
4287 if (!rSt.good())
4288 break;
4289 sal_uInt32 nUDData(0);
4290 rSt.ReadUInt32(nUDData);
4291 if (!rSt.good())
4292 break;
4293 if (nPID == 447)
4295 mbRotateGranientFillWithAngle = nUDData & 0x20;
4296 break;
4298 nBytesLeft -= 6;
4301 aObjData.bShapeType = maShapeRecords.SeekToContent( rSt, DFF_msofbtSp );
4302 if ( aObjData.bShapeType )
4304 sal_uInt32 temp(0);
4305 rSt.ReadUInt32( aObjData.nShapeId )
4306 .ReadUInt32( temp );
4307 aObjData.nSpFlags = ShapeFlag(temp);
4308 aObjData.eShapeType = static_cast<MSO_SPT>(maShapeRecords.Current()->nRecInstance);
4310 else
4312 aObjData.nShapeId = 0;
4313 aObjData.nSpFlags = ShapeFlag::NONE;
4314 aObjData.eShapeType = mso_sptNil;
4317 if( pShapeId )
4318 *pShapeId = aObjData.nShapeId;
4320 aObjData.bOpt = maShapeRecords.SeekToContent( rSt, DFF_msofbtOPT, SEEK_FROM_CURRENT_AND_RESTART );
4321 if ( aObjData.bOpt )
4323 if (!maShapeRecords.Current()->SeekToBegOfRecord(rSt))
4324 return nullptr;
4325 #ifdef DBG_AUTOSHAPE
4326 ReadPropSet( rSt, &rClientData, (sal_uInt32)aObjData.eShapeType );
4327 #else
4328 ReadPropSet( rSt, &rClientData );
4329 #endif
4331 else
4333 InitializePropSet( DFF_msofbtOPT ); // get the default PropSet
4334 static_cast<DffPropertyReader*>(this)->mnFix16Angle = 0_deg100;
4337 aObjData.bOpt2 = maShapeRecords.SeekToContent( rSt, DFF_msofbtUDefProp, SEEK_FROM_CURRENT_AND_RESTART );
4338 if ( aObjData.bOpt2 )
4340 maShapeRecords.Current()->SeekToBegOfRecord( rSt );
4341 pSecPropSet.reset( new DffPropertyReader( *this ) );
4342 pSecPropSet->ReadPropSet( rSt, nullptr );
4345 aObjData.bChildAnchor = maShapeRecords.SeekToContent( rSt, DFF_msofbtChildAnchor, SEEK_FROM_CURRENT_AND_RESTART );
4346 if ( aObjData.bChildAnchor )
4348 sal_Int32 l(0), o(0), r(0), u(0);
4349 rSt.ReadInt32( l ).ReadInt32( o ).ReadInt32( r ).ReadInt32( u );
4350 Scale( l );
4351 Scale( o );
4352 Scale( r );
4353 Scale( u );
4354 aObjData.aChildAnchor = tools::Rectangle( l, o, r, u );
4355 sal_Int32 nWidth, nHeight;
4356 if (!rGlobalChildRect.IsEmpty() && !rClientRect.IsEmpty() && rGlobalChildRect.GetWidth() && rGlobalChildRect.GetHeight() &&
4357 !o3tl::checked_sub(r, l, nWidth) && !o3tl::checked_sub(u, o, nHeight))
4359 double fXScale = static_cast<double>(rClientRect.GetWidth()) / static_cast<double>(rGlobalChildRect.GetWidth());
4360 double fYScale = static_cast<double>(rClientRect.GetHeight()) / static_cast<double>(rGlobalChildRect.GetHeight());
4361 double fl = ( ( l - rGlobalChildRect.Left() ) * fXScale ) + rClientRect.Left();
4362 double fo = ( ( o - rGlobalChildRect.Top() ) * fYScale ) + rClientRect.Top();
4363 double fWidth = nWidth * fXScale;
4364 double fHeight = nHeight * fYScale;
4365 aObjData.aChildAnchor = tools::Rectangle( Point( fl, fo ), Size( fWidth + 1, fHeight + 1 ) );
4369 aObjData.bClientAnchor = maShapeRecords.SeekToContent( rSt, DFF_msofbtClientAnchor, SEEK_FROM_CURRENT_AND_RESTART );
4370 if ( aObjData.bClientAnchor )
4371 ProcessClientAnchor2( rSt, *maShapeRecords.Current(), aObjData );
4373 if ( aObjData.bChildAnchor )
4374 aObjData.aBoundRect = aObjData.aChildAnchor;
4376 if ( aObjData.nSpFlags & ShapeFlag::Background )
4377 aObjData.aBoundRect = tools::Rectangle( Point(), Size( 1, 1 ) );
4379 rtl::Reference<SdrObject> xRet;
4381 tools::Rectangle aTextRect;
4382 if ( !aObjData.aBoundRect.IsEmpty() )
4383 { // apply rotation to the BoundingBox BEFORE an object has been generated
4384 if( mnFix16Angle )
4386 Degree100 nAngle = mnFix16Angle;
4387 if ( ( nAngle > 4500_deg100 && nAngle <= 13500_deg100 ) || ( nAngle > 22500_deg100 && nAngle <= 31500_deg100 ) )
4389 sal_Int32 nHalfWidth = ( aObjData.aBoundRect.GetWidth() + 1 ) >> 1;
4390 sal_Int32 nHalfHeight = ( aObjData.aBoundRect.GetHeight() + 1 ) >> 1;
4391 Point aTopLeft( aObjData.aBoundRect.Left() + nHalfWidth - nHalfHeight,
4392 aObjData.aBoundRect.Top() + nHalfHeight - nHalfWidth );
4393 Size aNewSize( aObjData.aBoundRect.GetHeight(), aObjData.aBoundRect.GetWidth() );
4394 tools::Rectangle aNewRect( aTopLeft, aNewSize );
4395 aObjData.aBoundRect = aNewRect;
4398 aTextRect = aObjData.aBoundRect;
4399 bool bGraphic = IsProperty( DFF_Prop_pib ) ||
4400 IsProperty( DFF_Prop_pibName ) ||
4401 IsProperty( DFF_Prop_pibFlags );
4403 if ( aObjData.nSpFlags & ShapeFlag::Group )
4405 xRet = new SdrObjGroup(*pSdrModel);
4406 /* After CWS aw033 has been integrated, an empty group object
4407 cannot store its resulting bounding rectangle anymore. We have
4408 to return this rectangle via rClientRect now, but only, if
4409 caller has not passed an own bounding ractangle. */
4410 if ( rClientRect.IsEmpty() )
4411 rClientRect = aObjData.aBoundRect;
4412 nGroupShapeFlags = aObjData.nSpFlags;
4414 else if ( ( aObjData.eShapeType != mso_sptNil ) || IsProperty( DFF_Prop_pVertices ) || bGraphic )
4416 SfxItemSet aSet( pSdrModel->GetItemPool() );
4418 bool bIsConnector = ( ( aObjData.eShapeType >= mso_sptStraightConnector1 ) && ( aObjData.eShapeType <= mso_sptCurvedConnector5 ) );
4419 Degree100 nObjectRotation = mnFix16Angle;
4420 ShapeFlag nSpFlags = aObjData.nSpFlags;
4422 if ( bGraphic )
4424 if (!mbSkipImages) {
4425 xRet = ImportGraphic(rSt, aSet, aObjData); // SJ: #68396# is no longer true (fixed in ppt2000)
4426 ApplyAttributes( rSt, aSet, aObjData );
4427 xRet->SetMergedItemSet(aSet);
4430 else if ( aObjData.eShapeType == mso_sptLine && !( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 8 ) )
4432 basegfx::B2DPolygon aPoly;
4433 aPoly.append(basegfx::B2DPoint(aObjData.aBoundRect.Left(), aObjData.aBoundRect.Top()));
4434 aPoly.append(basegfx::B2DPoint(aObjData.aBoundRect.Right(), aObjData.aBoundRect.Bottom()));
4435 xRet = new SdrPathObj(
4436 *pSdrModel,
4437 SdrObjKind::Line,
4438 basegfx::B2DPolyPolygon(aPoly));
4439 ApplyAttributes( rSt, aSet, aObjData );
4440 xRet->SetMergedItemSet(aSet);
4442 else
4444 if ( GetCustomShapeContent( aObjData.eShapeType ) || IsProperty( DFF_Prop_pVertices ) )
4447 ApplyAttributes( rSt, aSet, aObjData );
4449 xRet = new SdrObjCustomShape(*pSdrModel);
4451 sal_uInt32 ngtextFStrikethrough = GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 );
4452 bool bIsFontwork = ( ngtextFStrikethrough & 0x4000 ) != 0;
4454 // in case of a FontWork, the text is set by the escher import
4455 if ( bIsFontwork )
4457 OUString aObjectText;
4458 OUString aFontName;
4460 if ( SeekToContent( DFF_Prop_gtextFont, rSt ) )
4462 SvxFontItem aLatin(EE_CHAR_FONTINFO), aAsian(EE_CHAR_FONTINFO_CJK), aComplex(EE_CHAR_FONTINFO_CTL);
4463 GetDefaultFonts( aLatin, aAsian, aComplex );
4465 aFontName = MSDFFReadZString( rSt, GetPropertyValue( DFF_Prop_gtextFont, 0 ), true );
4466 aSet.Put( SvxFontItem( aLatin.GetFamily(), aFontName, aLatin.GetStyleName(),
4467 PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, EE_CHAR_FONTINFO ));
4468 aSet.Put( SvxFontItem( aLatin.GetFamily(), aFontName, aLatin.GetStyleName(),
4469 PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, EE_CHAR_FONTINFO_CJK ) );
4470 aSet.Put( SvxFontItem( aLatin.GetFamily(), aFontName, aLatin.GetStyleName(),
4471 PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, EE_CHAR_FONTINFO_CTL ) );
4474 // SJ: applying fontattributes for Fontwork :
4475 if ( IsHardAttribute( DFF_Prop_gtextFItalic ) )
4476 aSet.Put( SvxPostureItem( ( ngtextFStrikethrough & 0x0010 ) != 0 ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC ) );
4478 if ( IsHardAttribute( DFF_Prop_gtextFBold ) )
4479 aSet.Put( SvxWeightItem( ( ngtextFStrikethrough & 0x0020 ) != 0 ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT ) );
4481 // SJ TODO: Vertical Writing is not correct, instead
4482 // this should be replaced through "CharacterRotation"
4483 // by 90 degrees, therefore a new Item has to be
4484 // supported by svx core, api and xml file format
4485 static_cast<SdrObjCustomShape*>(xRet.get())->SetVerticalWriting( ( ngtextFStrikethrough & 0x2000 ) != 0 );
4487 if ( SeekToContent( DFF_Prop_gtextUNICODE, rSt ) )
4489 aObjectText = MSDFFReadZString( rSt, GetPropertyValue( DFF_Prop_gtextUNICODE, 0 ), true );
4490 ReadObjText(aObjectText, xRet.get());
4493 auto eGeoTextAlign = GetPropertyValue(DFF_Prop_gtextAlign, mso_alignTextCenter);
4495 SdrTextHorzAdjust eHorzAdjust;
4496 switch( eGeoTextAlign )
4498 case mso_alignTextLetterJust :
4499 case mso_alignTextWordJust :
4500 case mso_alignTextStretch : eHorzAdjust = SDRTEXTHORZADJUST_BLOCK; break;
4501 default:
4502 case mso_alignTextInvalid :
4503 case mso_alignTextCenter : eHorzAdjust = SDRTEXTHORZADJUST_CENTER; break;
4504 case mso_alignTextLeft : eHorzAdjust = SDRTEXTHORZADJUST_LEFT; break;
4505 case mso_alignTextRight : eHorzAdjust = SDRTEXTHORZADJUST_RIGHT; break;
4507 aSet.Put( SdrTextHorzAdjustItem( eHorzAdjust ) );
4509 drawing::TextFitToSizeType eFTS = drawing::TextFitToSizeType_NONE;
4510 if ( eGeoTextAlign == mso_alignTextStretch )
4511 eFTS = drawing::TextFitToSizeType_ALLLINES;
4512 aSet.Put( SdrTextFitToSizeTypeItem( eFTS ) );
4514 if ( IsProperty( DFF_Prop_gtextSpacing ) )
4516 sal_Int32 nTextWidth = GetPropertyValue( DFF_Prop_gtextSpacing, 1 << 16 ) / 655;
4517 if ( nTextWidth != 100 )
4518 aSet.Put( SvxCharScaleWidthItem( static_cast<sal_uInt16>(nTextWidth), EE_CHAR_FONTWIDTH ) );
4520 if ( ngtextFStrikethrough & 0x1000 ) // SJ: Font Kerning On ?
4521 aSet.Put( SvxKerningItem( 1, EE_CHAR_KERNING ) );
4523 // #i119496# the resize autoshape to fit text attr of word art in MS PPT is always false
4524 aSet.Put(makeSdrTextAutoGrowHeightItem(false));
4525 aSet.Put(makeSdrTextAutoGrowWidthItem(false));
4527 bool bWithPadding = !( ngtextFStrikethrough & use_gtextFBestFit
4528 && ngtextFStrikethrough & use_gtextFShrinkFit
4529 && ngtextFStrikethrough & use_gtextFStretch
4530 && ngtextFStrikethrough & gtextFBestFit
4531 && ngtextFStrikethrough & gtextFShrinkFit
4532 && ngtextFStrikethrough & gtextFStretch );
4534 if ( bWithPadding )
4536 // trim, remove additional space
4537 VclPtr<VirtualDevice> pDevice = VclPtr<VirtualDevice>::Create();
4538 vcl::Font aFont = pDevice->GetFont();
4539 aFont.SetFamilyName( aFontName );
4540 aFont.SetFontSize( Size( 0, 96 ) );
4541 pDevice->SetFont( aFont );
4543 auto nTextWidth = pDevice->GetTextWidth( aObjectText );
4544 OUString aObjName = GetPropertyString( DFF_Prop_wzName, rSt );
4545 if ( nTextWidth && aObjData.eShapeType == mso_sptTextPlainText
4546 && aObjName.match( "PowerPlusWaterMarkObject" ) )
4548 double fRatio = static_cast<double>(pDevice->GetTextHeight()) / nTextWidth;
4549 sal_Int32 nNewHeight = fRatio * aObjData.aBoundRect.getOpenWidth();
4550 sal_Int32 nPaddingY = aObjData.aBoundRect.getOpenHeight() - nNewHeight;
4552 if ( nPaddingY > 0 )
4553 aObjData.aBoundRect.setHeight( nNewHeight );
4557 xRet->SetMergedItemSet( aSet );
4559 // sj: taking care of rtl, ltr. In case of fontwork mso. seems not to be able to set
4560 // proper text directions, instead the text default is depending to the string.
4561 // so we have to calculate the a text direction from string:
4562 if ( bIsFontwork )
4564 OutlinerParaObject* pParaObj = static_cast<SdrObjCustomShape*>(xRet.get())->GetOutlinerParaObject();
4565 if ( pParaObj )
4567 SdrOutliner& rOutliner = static_cast<SdrObjCustomShape*>(xRet.get())->ImpGetDrawOutliner();
4568 rOutliner.SetStyleSheetPool(static_cast< SfxStyleSheetPool* >(xRet->getSdrModelFromSdrObject().GetStyleSheetPool()));
4569 bool bOldUpdateMode = rOutliner.SetUpdateLayout( false );
4570 rOutliner.SetText( *pParaObj );
4571 ScopedVclPtrInstance< VirtualDevice > pVirDev(DeviceFormat::WITHOUT_ALPHA);
4572 pVirDev->SetMapMode(MapMode(MapUnit::Map100thMM));
4573 sal_Int32 i, nParagraphs = rOutliner.GetParagraphCount();
4574 if ( nParagraphs )
4576 bool bCreateNewParaObject = false;
4577 for ( i = 0; i < nParagraphs; i++ )
4579 OUString aString(rOutliner.GetText(rOutliner.GetParagraph(i)));
4580 bool bIsRTL = pVirDev->GetTextIsRTL(aString, 0, aString.getLength());
4581 if ( bIsRTL )
4583 SfxItemSet aSet2( rOutliner.GetParaAttribs( i ) );
4584 aSet2.Put( SvxFrameDirectionItem( SvxFrameDirection::Horizontal_RL_TB, EE_PARA_WRITINGDIR ) );
4585 rOutliner.SetParaAttribs( i, aSet2 );
4586 bCreateNewParaObject = true;
4589 if ( bCreateNewParaObject )
4591 std::optional<OutlinerParaObject> pNewText = rOutliner.CreateParaObject();
4592 rOutliner.Init( OutlinerMode::TextObject );
4593 static_cast<SdrObjCustomShape*>(xRet.get())->NbcSetOutlinerParaObject( std::move(pNewText) );
4596 rOutliner.Clear();
4597 rOutliner.SetUpdateLayout( bOldUpdateMode );
4601 // mso_sptArc special treating
4602 // tdf#124029: A new custom shape is generated from prototype 'msoArc'. Values, which are
4603 // read here, are adapted and merged. The shape type is changed, so this code
4604 // applies only if importing arcs from MS Office.
4605 if ( aObjData.eShapeType == mso_sptArc )
4607 static constexpr OUString sAdjustmentValues( u"AdjustmentValues"_ustr );
4608 static constexpr OUString sViewBox( u"ViewBox"_ustr );
4609 static constexpr OUString sPath( u"Path"_ustr );
4610 SdrCustomShapeGeometryItem aGeometryItem( static_cast<SdrObjCustomShape*>(xRet.get())->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
4611 PropertyValue aPropVal;
4613 // The default arc goes form -90deg to 0deg. Replace general defaults used
4614 // when read from stream with this specific values.
4615 double fStartAngle(-90.0);
4616 double fEndAngle(0.0);
4617 css::uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > seqAdjustmentValues;
4618 const uno::Any* pAny = aGeometryItem.GetPropertyValueByName(sAdjustmentValues);
4619 if (pAny && (*pAny >>= seqAdjustmentValues) && seqAdjustmentValues.getLength() > 1)
4621 auto pseqAdjustmentValues = seqAdjustmentValues.getArray();
4622 if (seqAdjustmentValues[0].State == css::beans::PropertyState_DEFAULT_VALUE)
4624 pseqAdjustmentValues[0].Value <<= -90.0;
4625 pseqAdjustmentValues[0].State = css::beans::PropertyState_DIRECT_VALUE;
4627 if (seqAdjustmentValues[1].State == css::beans::PropertyState_DEFAULT_VALUE)
4629 pseqAdjustmentValues[1].Value <<= 0.0;
4630 pseqAdjustmentValues[1].State = css::beans::PropertyState_DIRECT_VALUE;
4632 seqAdjustmentValues[0].Value >>= fStartAngle;
4633 seqAdjustmentValues[1].Value >>= fEndAngle;
4634 aPropVal.Name = sAdjustmentValues;
4635 aPropVal.Value <<= seqAdjustmentValues;
4636 aGeometryItem.SetPropertyValue(aPropVal);
4639 // arc first command is always wr -- clockwise arc
4640 // the parameters are : (left,top),(right,bottom),start(x,y),end(x,y)
4641 // The left/top vertex of the frame rectangle of the sector is the origin
4642 // of the shape internal coordinate system in MS Office. The default arc
4643 // has an ellipse frame rectangle with LT(-21600,0) and
4644 // RB(21600,43200) in this coordinate system.
4645 basegfx::B2DRectangle aEllipseRect_MS(-21600.0, 0.0, 21600.0, 43200.0);
4646 css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> seqCoordinates;
4647 pAny = aGeometryItem.GetPropertyValueByName( sPath, u"Coordinates"_ustr );
4648 if (pAny && (*pAny >>= seqCoordinates) && (seqCoordinates.getLength() >= 2))
4650 auto const nL
4651 = *o3tl::doAccess<sal_Int32>(seqCoordinates[0].First.Value);
4652 auto const nT
4653 = *o3tl::doAccess<sal_Int32>(seqCoordinates[0].Second.Value);
4654 auto const nR
4655 = *o3tl::doAccess<sal_Int32>(seqCoordinates[1].First.Value);
4656 auto const nB
4657 = *o3tl::doAccess<sal_Int32>(seqCoordinates[1].Second.Value);
4658 aEllipseRect_MS = basegfx::B2DRectangle(nL, nT, nR, nB);
4661 // MS Office uses the pie frame rectangle as reference for outer position
4662 // and size of the shape and for text in the shape. We can get this rectangle
4663 // from imported viewBox or from the arc geometry.
4664 basegfx::B2DRectangle aPieRect_MS(0.0 , 0.0, 21600.0, 21600.0);
4665 pAny = aGeometryItem.GetPropertyValueByName(sPath,sViewBox);
4666 css::awt::Rectangle aImportedViewBox;
4667 if (pAny && (*pAny >>= aImportedViewBox))
4669 aPieRect_MS = basegfx::B2DRectangle( aImportedViewBox.X,
4670 aImportedViewBox.Y,
4671 aImportedViewBox.X + aImportedViewBox.Width,
4672 aImportedViewBox.Y + aImportedViewBox.Height);
4674 else
4676 double fRadStartAngle(basegfx::deg2rad(NormAngle360(fStartAngle)));
4677 double fRadEndAngle(basegfx::deg2rad(NormAngle360(fEndAngle)));
4678 basegfx::B2DPoint aCenter(aEllipseRect_MS.getCenter());
4679 basegfx::B2DPolygon aTempPie(
4680 basegfx::utils::createPolygonFromEllipseSegment(
4681 aCenter,
4682 aEllipseRect_MS.getWidth() * 0.5,
4683 aEllipseRect_MS.getHeight() * 0.5,
4684 fRadStartAngle,
4685 fRadEndAngle));
4686 aTempPie.append(aCenter);
4687 aPieRect_MS = aTempPie.getB2DRange();
4690 // MS Office uses for mso_sptArc a frame rectangle (=resize handles)
4691 // which encloses only the sector, LibreOffice uses for custom shapes as
4692 // default a frame rectangle, which encloses the entire ellipse. That would
4693 // result in wrong positions in Writer and Calc, see tdf#124029.
4694 // We workaround this problem, by setting a suitable viewBox.
4695 bool bIsImportPPT(GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_PPT);
4696 if (bIsImportPPT || aPieRect_MS.getWidth() == 0 || aPieRect_MS.getHeight() == 0)
4697 { // clear item, so that default from EnhancedCustomShapeGeometry is used
4698 aGeometryItem.ClearPropertyValue(sViewBox);
4700 else
4702 double fX((aPieRect_MS.getMinX() - aEllipseRect_MS.getMinX()) / 2.0);
4703 double fY((aPieRect_MS.getMinY() - aEllipseRect_MS.getMinY()) / 2.0);
4704 css::awt::Rectangle aViewBox_LO; // in LO coordinate system
4705 aViewBox_LO.X = static_cast<sal_Int32>(fX);
4706 aViewBox_LO.Y = static_cast<sal_Int32>(fY);
4707 aViewBox_LO.Width = static_cast<sal_Int32>(aPieRect_MS.getWidth() / 2.0);
4708 aViewBox_LO.Height = static_cast<sal_Int32>(aPieRect_MS.getHeight() / 2.0);
4709 aPropVal.Name = sViewBox;
4710 aPropVal.Value <<= aViewBox_LO;
4711 aGeometryItem.SetPropertyValue(aPropVal);
4714 // aObjData.aBoundRect contains position and size of the sector in (outer)
4715 // logic coordinates, e.g. for PPT in 1/100 mm, for Word in twips.
4716 // For Impress the default viewBox is used, so adapt aObjData.aBoundRect.
4717 tools::Rectangle aOldBoundRect(aObjData.aBoundRect); // backup, needed later on
4718 if (bIsImportPPT)
4720 double fLogicXOfs(0.0); // LogicLeft_LO = LogicLeft_MS + fXLogicOfs
4721 double fLogicYOfs(0.0);
4722 double fLogicPieWidth(aObjData.aBoundRect.getOpenWidth());
4723 double fLogicPieHeight(aObjData.aBoundRect.getOpenHeight());
4724 double fLogicEllipseWidth(0.0); // to be LogicWidth_LO
4725 double fLogicEllipseHeight(0.0);
4726 if (aPieRect_MS.getWidth())
4728 // fXScale = ratio 'logic length' : 'shape internal length'
4729 double fXScale = fLogicPieWidth / aPieRect_MS.getWidth();
4730 if (nSpFlags & ShapeFlag::FlipH)
4731 fLogicXOfs = (aPieRect_MS.getMaxX() - aEllipseRect_MS.getMaxX()) * fXScale;
4732 else
4733 fLogicXOfs = (aEllipseRect_MS.getMinX() - aPieRect_MS.getMinX()) * fXScale;
4734 fLogicEllipseWidth = aEllipseRect_MS.getWidth() * fXScale;
4736 if (aPieRect_MS.getHeight())
4738 double fYScale = fLogicPieHeight / aPieRect_MS.getHeight();
4739 if (nSpFlags & ShapeFlag::FlipV)
4740 fLogicYOfs = (aPieRect_MS.getMaxY() - aEllipseRect_MS.getMaxY()) * fYScale;
4741 else
4742 fLogicYOfs = (aEllipseRect_MS.getMinY() - aPieRect_MS.getMinY()) * fYScale;
4743 fLogicEllipseHeight = aEllipseRect_MS.getHeight() * fYScale;
4745 aObjData.aBoundRect = tools::Rectangle(
4746 Point(aOldBoundRect.Left() + static_cast<sal_Int32>(fLogicXOfs),
4747 aOldBoundRect.Top() + static_cast<sal_Int32>(fLogicYOfs)),
4748 Size(static_cast<sal_Int32>(fLogicEllipseWidth),
4749 static_cast<sal_Int32>(fLogicEllipseHeight)));
4751 // else nothing to do. aObjData.aBoundRect corresponds to changed viewBox.
4753 // creating the text frame -> scaling into (0,0),(21600,21600) destination coordinate system
4754 double fTextFrameScaleX = 0.0;
4755 double fTextFrameScaleY = 0.0;
4756 if (aEllipseRect_MS.getWidth())
4757 fTextFrameScaleX = 21600.0 / aEllipseRect_MS.getWidth();
4758 if (aEllipseRect_MS.getHeight())
4759 fTextFrameScaleY = 21600.0 / aEllipseRect_MS.getHeight();
4761 sal_Int32 nLeft = static_cast<sal_Int32>((aPieRect_MS.getMinX() - aEllipseRect_MS.getMinX()) * fTextFrameScaleX );
4762 sal_Int32 nTop = static_cast<sal_Int32>((aPieRect_MS.getMinY() - aEllipseRect_MS.getMinY()) * fTextFrameScaleY );
4763 sal_Int32 nRight = static_cast<sal_Int32>((aPieRect_MS.getMaxX() - aEllipseRect_MS.getMinX()) * fTextFrameScaleX );
4764 sal_Int32 nBottom= static_cast<sal_Int32>((aPieRect_MS.getMaxY() - aEllipseRect_MS.getMinY()) * fTextFrameScaleY );
4765 css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aTextFrame( 1 );
4766 auto pTextFrame = aTextFrame.getArray();
4767 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pTextFrame[ 0 ].TopLeft.First, nLeft );
4768 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pTextFrame[ 0 ].TopLeft.Second, nTop );
4769 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pTextFrame[ 0 ].BottomRight.First, nRight );
4770 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pTextFrame[ 0 ].BottomRight.Second,nBottom );
4771 PropertyValue aProp;
4772 aProp.Name = "TextFrames";
4773 aProp.Value <<= aTextFrame;
4774 aGeometryItem.SetPropertyValue( sPath, aProp );
4776 // sj: taking care of the different rotation points, since the new arc is having a bigger snaprect
4777 if ( mnFix16Angle )
4779 Degree100 nAngle = mnFix16Angle;
4780 if ( nSpFlags & ShapeFlag::FlipH )
4781 nAngle = 36000_deg100 - nAngle;
4782 if ( nSpFlags & ShapeFlag::FlipV )
4783 nAngle = -nAngle;
4784 double a = toRadians(nAngle);
4785 double ss = sin( a );
4786 double cc = cos( a );
4787 Point aP1( aOldBoundRect.TopLeft() );
4788 Point aC1( aObjData.aBoundRect.Center() );
4789 Point aP2( aOldBoundRect.TopLeft() );
4790 Point aC2( aOldBoundRect.Center() );
4791 RotatePoint( aP1, aC1, ss, cc );
4792 RotatePoint( aP2, aC2, ss, cc );
4793 aObjData.aBoundRect.Move( aP2.X() - aP1.X(), aP2.Y() - aP1.Y() );
4796 // clearing items, so MergeDefaultAttributes will set the corresponding
4797 // defaults from EnhancedCustomShapeGeometry
4798 aGeometryItem.ClearPropertyValue( u"Handles"_ustr );
4799 aGeometryItem.ClearPropertyValue( u"Equations"_ustr );
4800 aGeometryItem.ClearPropertyValue( sPath );
4802 static_cast<SdrObjCustomShape*>(xRet.get())->SetMergedItem( aGeometryItem );
4803 static_cast<SdrObjCustomShape*>(xRet.get())->MergeDefaultAttributes();
4805 // now setting a new name, so the above correction is only done once when importing from ms
4806 SdrCustomShapeGeometryItem aGeoName( static_cast<SdrObjCustomShape*>(xRet.get())->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
4807 aPropVal.Name = "Type";
4808 aPropVal.Value <<= u"mso-spt100"_ustr;
4809 aGeoName.SetPropertyValue( aPropVal );
4810 static_cast<SdrObjCustomShape*>(xRet.get())->SetMergedItem( aGeoName );
4812 else
4813 static_cast<SdrObjCustomShape*>(xRet.get())->MergeDefaultAttributes();
4815 xRet->SetSnapRect( aObjData.aBoundRect );
4816 EnhancedCustomShape2d aCustomShape2d(static_cast<SdrObjCustomShape&>(*xRet));
4817 aTextRect = aCustomShape2d.GetTextRect();
4819 if( bIsConnector )
4821 if( nObjectRotation )
4822 xRet->NbcRotate( aObjData.aBoundRect.Center(), nObjectRotation );
4823 // mirrored horizontally?
4824 if ( nSpFlags & ShapeFlag::FlipH )
4826 tools::Rectangle aBndRect(xRet->GetSnapRect());
4827 Point aTop( ( aBndRect.Left() + aBndRect.Right() ) >> 1, aBndRect.Top() );
4828 Point aBottom( aTop.X(), aTop.Y() + 1000 );
4829 xRet->NbcMirror( aTop, aBottom );
4831 // mirrored vertically?
4832 if ( nSpFlags & ShapeFlag::FlipV )
4834 tools::Rectangle aBndRect(xRet->GetSnapRect());
4835 Point aLeft( aBndRect.Left(), ( aBndRect.Top() + aBndRect.Bottom() ) >> 1 );
4836 Point aRight( aLeft.X() + 1000, aLeft.Y() );
4837 xRet->NbcMirror( aLeft, aRight );
4839 basegfx::B2DPolyPolygon aPoly( static_cast<SdrObjCustomShape*>(xRet.get())->GetLineGeometry( true ) );
4841 xRet = new SdrEdgeObj(*pSdrModel);
4842 ApplyAttributes( rSt, aSet, aObjData );
4843 xRet->SetLogicRect( aObjData.aBoundRect );
4844 xRet->SetMergedItemSet(aSet);
4846 // connectors
4847 auto eConnectorStyle = GetPropertyValue(DFF_Prop_cxstyle, mso_cxstyleStraight);
4849 static_cast<SdrEdgeObj*>(xRet.get())->ConnectToNode(true, nullptr);
4850 static_cast<SdrEdgeObj*>(xRet.get())->ConnectToNode(false, nullptr);
4852 Point aPoint1( aObjData.aBoundRect.TopLeft() );
4853 Point aPoint2( aObjData.aBoundRect.BottomRight() );
4855 // pay attention to the rotations
4856 if ( nObjectRotation )
4858 double a = toRadians(nObjectRotation);
4859 Point aCenter( aObjData.aBoundRect.Center() );
4860 double ss = sin(a);
4861 double cc = cos(a);
4863 RotatePoint(aPoint1, aCenter, ss, cc);
4864 RotatePoint(aPoint2, aCenter, ss, cc);
4866 // #i120437# reset rotation, it is part of the path and shall not be applied again
4867 nObjectRotation = 0_deg100;
4870 // rotate/mirror line within the area as we need it
4871 if ( nSpFlags & ShapeFlag::FlipH )
4873 sal_Int32 n = aPoint1.X();
4874 aPoint1.setX( aPoint2.X() );
4875 aPoint2.setX( n );
4877 // #i120437# reset hor flip
4878 nSpFlags &= ~ShapeFlag::FlipH;
4880 if ( nSpFlags & ShapeFlag::FlipV )
4882 sal_Int32 n = aPoint1.Y();
4883 aPoint1.setY( aPoint2.Y() );
4884 aPoint2.setY( n );
4886 // #i120437# reset ver flip
4887 nSpFlags &= ~ShapeFlag::FlipV;
4890 xRet->NbcSetPoint(aPoint1, 0); // start point
4891 xRet->NbcSetPoint(aPoint2, 1); // endpoint
4893 sal_Int32 n1HorzDist, n1VertDist, n2HorzDist, n2VertDist;
4894 n1HorzDist = n1VertDist = n2HorzDist = n2VertDist = 0;
4895 switch( eConnectorStyle )
4897 case mso_cxstyleBent:
4899 aSet.Put( SdrEdgeKindItem( SdrEdgeKind::OrthoLines ) );
4900 n1HorzDist = n1VertDist = n2HorzDist = n2VertDist = 630;
4902 break;
4903 case mso_cxstyleCurved:
4904 aSet.Put( SdrEdgeKindItem( SdrEdgeKind::Bezier ) );
4905 break;
4906 default: // mso_cxstyleStraight || mso_cxstyleNone
4907 aSet.Put( SdrEdgeKindItem( SdrEdgeKind::OneLine ) );
4908 break;
4910 aSet.Put( SdrEdgeNode1HorzDistItem( n1HorzDist ) );
4911 aSet.Put( SdrEdgeNode1VertDistItem( n1VertDist ) );
4912 aSet.Put( SdrEdgeNode2HorzDistItem( n2HorzDist ) );
4913 aSet.Put( SdrEdgeNode2VertDistItem( n2VertDist ) );
4915 static_cast<SdrEdgeObj*>(xRet.get())->SetEdgeTrackPath( aPoly );
4916 xRet->SetMergedItemSet(aSet);
4918 if ( aObjData.eShapeType == mso_sptLine )
4920 xRet->SetMergedItemSet(aSet);
4921 static_cast<SdrObjCustomShape*>(xRet.get())->MergeDefaultAttributes();
4926 if (xRet)
4928 if( nObjectRotation )
4929 xRet->NbcRotate( aObjData.aBoundRect.Center(), nObjectRotation );
4930 // mirrored horizontally?
4931 if ( nSpFlags & ShapeFlag::FlipH )
4933 tools::Rectangle aBndRect(xRet->GetSnapRect());
4934 Point aTop( ( aBndRect.Left() + aBndRect.Right() ) >> 1, aBndRect.Top() );
4935 Point aBottom( aTop.X(), aTop.Y() + 1000 );
4936 xRet->NbcMirror(aTop, aBottom);
4938 // mirrored vertically?
4939 if ( nSpFlags & ShapeFlag::FlipV )
4941 tools::Rectangle aBndRect(xRet->GetSnapRect());
4942 Point aLeft( aBndRect.Left(), ( aBndRect.Top() + aBndRect.Bottom() ) >> 1 );
4943 Point aRight( aLeft.X() + 1000, aLeft.Y() );
4944 xRet->NbcMirror(aLeft, aRight);
4950 // #i51348# #118052# name of the shape
4951 if (xRet)
4953 OUString aObjName = GetPropertyString( DFF_Prop_wzName, rSt );
4954 if( !aObjName.isEmpty() )
4955 xRet->SetName(aObjName);
4958 xRet = ProcessObj(rSt, aObjData, rClientData, aTextRect, xRet.get());
4960 if (xRet)
4962 sal_Int32 nGroupProperties( GetPropertyValue( DFF_Prop_fPrint, 0 ) );
4963 const bool bVisible = ( ( nGroupProperties & 2 ) == 0 );
4964 xRet->SetVisible( bVisible );
4965 // In Excel hidden means not printed
4966 if ( !bVisible )
4968 xRet->SetPrintable(false);
4970 else
4972 // This property isn't used in Excel anymore, leaving it for legacy reasons
4973 xRet->SetPrintable( ( nGroupProperties & 1 ) != 0 );
4977 //Import alt text as description
4978 if (xRet && SeekToContent(DFF_Prop_wzDescription, rSt))
4980 OUString aAltText = MSDFFReadZString(rSt, GetPropertyValue(DFF_Prop_wzDescription, 0), true);
4981 xRet->SetDescription(aAltText);
4984 // If this shape opens a new group, push back its object data because
4985 // finalization will be called when nested objects have been imported;
4986 // otherwise, just finalize here
4987 if (o3tl::make_unsigned(nCalledByGroup) > maPendingGroupData.size())
4989 auto xHdClone = std::make_shared<DffRecordHeader>(aObjData.rSpHd);
4990 maPendingGroupData.emplace_back(DffObjData(xHdClone, aObjData), xHdClone );
4992 else
4994 xRet = FinalizeObj(aObjData, xRet.get());
4996 return xRet;
4999 tools::Rectangle SvxMSDffManager::GetGlobalChildAnchor( const DffRecordHeader& rHd, SvStream& rSt, tools::Rectangle& aClientRect )
5001 tools::Rectangle aChildAnchor;
5002 if (!rHd.SeekToContent(rSt))
5003 return aChildAnchor;
5005 bool bIsClientRectRead = false;
5006 while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < rHd.GetRecEndFilePos() ) )
5008 DffRecordHeader aShapeHd;
5009 if (!ReadDffRecordHeader(rSt, aShapeHd))
5010 break;
5011 if ( ( aShapeHd.nRecType == DFF_msofbtSpContainer ) ||
5012 ( aShapeHd.nRecType == DFF_msofbtSpgrContainer ) )
5014 DffRecordHeader aShapeHd2( aShapeHd );
5015 if ( aShapeHd.nRecType == DFF_msofbtSpgrContainer )
5016 ReadDffRecordHeader( rSt, aShapeHd2 );
5017 while (rSt.good() && rSt.Tell() < aShapeHd2.GetRecEndFilePos())
5019 DffRecordHeader aShapeAtom;
5020 if (!ReadDffRecordHeader(rSt, aShapeAtom))
5021 break;
5023 if ( aShapeAtom.nRecType == DFF_msofbtClientAnchor )
5025 if ( GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_PPT )
5027 sal_Int32 l(0), t(0), r(0), b(0);
5028 if ( aShapeAtom.nRecLen == 16 )
5030 rSt.ReadInt32( l ).ReadInt32( t ).ReadInt32( r ).ReadInt32( b );
5032 else
5034 sal_Int16 ls(0), ts(0), rs(0), bs(0);
5035 rSt.ReadInt16( ts ).ReadInt16( ls ).ReadInt16( rs ).ReadInt16( bs ); // the order of coordinates is a bit strange...
5036 l = ls;
5037 t = ts;
5038 r = rs;
5039 b = bs;
5041 Scale( l );
5042 Scale( t );
5043 Scale( r );
5044 Scale( b );
5045 if ( bIsClientRectRead )
5047 tools::Rectangle aChild( l, t, r, b );
5048 aChildAnchor.Union( aChild );
5050 else
5052 aClientRect = tools::Rectangle( l, t, r, b );
5053 bIsClientRectRead = true;
5056 break;
5058 else if ( aShapeAtom.nRecType == DFF_msofbtChildAnchor )
5060 sal_Int32 l(0), o(0), r(0), u(0);
5061 rSt.ReadInt32( l ).ReadInt32( o ).ReadInt32( r ).ReadInt32( u );
5062 Scale( l );
5063 Scale( o );
5064 Scale( r );
5065 Scale( u );
5066 tools::Rectangle aChild( l, o, r, u );
5067 aChildAnchor.Union( aChild );
5068 break;
5070 if (!aShapeAtom.SeekToEndOfRecord(rSt))
5071 break;
5074 if (!aShapeHd.SeekToEndOfRecord(rSt))
5075 break;
5077 return aChildAnchor;
5080 void SvxMSDffManager::GetGroupAnchors( const DffRecordHeader& rHd, SvStream& rSt,
5081 tools::Rectangle& rGroupClientAnchor, tools::Rectangle& rGroupChildAnchor,
5082 const tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect )
5084 if (!rHd.SeekToContent(rSt))
5085 return;
5087 bool bFirst = true;
5088 DffRecordHeader aShapeHd;
5089 while (rSt.good() && rSt.Tell() < rHd.GetRecEndFilePos())
5091 if (!ReadDffRecordHeader(rSt, aShapeHd))
5092 break;
5093 if ( ( aShapeHd.nRecType == DFF_msofbtSpContainer ) ||
5094 ( aShapeHd.nRecType == DFF_msofbtSpgrContainer ) )
5096 DffRecordHeader aShapeHd2( aShapeHd );
5097 if ( aShapeHd.nRecType == DFF_msofbtSpgrContainer )
5098 ReadDffRecordHeader( rSt, aShapeHd2 );
5099 while (rSt.good() && rSt.Tell() < aShapeHd2.GetRecEndFilePos())
5101 DffRecordHeader aShapeAtom;
5102 if (!ReadDffRecordHeader(rSt, aShapeAtom))
5103 break;
5104 if ( aShapeAtom.nRecType == DFF_msofbtChildAnchor )
5106 sal_Int32 l(0), o(0), r(0), u(0);
5107 rSt.ReadInt32( l ).ReadInt32( o ).ReadInt32( r ).ReadInt32( u );
5108 Scale( l );
5109 Scale( o );
5110 Scale( r );
5111 Scale( u );
5112 tools::Rectangle aChild( l, o, r, u );
5114 if ( bFirst )
5116 if ( !rGlobalChildRect.IsEmpty() && !rClientRect.IsEmpty() && rGlobalChildRect.GetWidth() && rGlobalChildRect.GetHeight() )
5118 double fWidth = o3tl::saturating_sub(r, l);
5119 double fHeight= o3tl::saturating_sub(u, o);
5120 double fXScale = static_cast<double>(rClientRect.GetWidth()) / static_cast<double>(rGlobalChildRect.GetWidth());
5121 double fYScale = static_cast<double>(rClientRect.GetHeight()) / static_cast<double>(rGlobalChildRect.GetHeight());
5122 double fl = ( ( l - rGlobalChildRect.Left() ) * fXScale ) + rClientRect.Left();
5123 double fo = ( ( o - rGlobalChildRect.Top() ) * fYScale ) + rClientRect.Top();
5124 fWidth *= fXScale;
5125 fHeight *= fYScale;
5126 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 ) ) );
5128 bFirst = false;
5130 else
5131 rGroupChildAnchor.Union( aChild );
5132 break;
5134 if (!aShapeAtom.SeekToEndOfRecord(rSt))
5135 break;
5138 if (!aShapeHd.SeekToEndOfRecord(rSt))
5139 break;
5143 SvxMSDffImportRec* SvxMSDffImportData::find(const SdrObject* pObj)
5145 auto it = m_ObjToRecMap.find(pObj);
5146 if (it != m_ObjToRecMap.end())
5147 return it->second;
5148 return nullptr;
5151 void SvxMSDffImportData::insert(std::unique_ptr<SvxMSDffImportRec> pImpRec)
5153 auto aRet = m_Records.insert(std::move(pImpRec));
5154 bool bSuccess = aRet.second;
5155 if (bSuccess)
5157 SvxMSDffImportRec* pRec = aRet.first->get();
5158 m_ObjToRecMap[pRec->pObj.get()] = pRec;
5162 void SvxMSDffImportData::NotifyFreeObj(SdrObject* pObj)
5164 if (SvxMSDffImportRec* pRecord = find(pObj))
5166 m_ObjToRecMap.erase(pObj);
5167 pRecord->pObj = nullptr;
5171 void SvxMSDffManager::NotifyFreeObj(SvxMSDffClientData& rData, SdrObject* pObj)
5173 if (SdrObjGroup* pGroup = dynamic_cast<SdrObjGroup*>(pObj))
5175 SdrObjList* pSubList = pGroup->GetSubList();
5176 for (const rtl::Reference<SdrObject>& pChildObj : *pSubList)
5177 NotifyFreeObj(rData, pChildObj.get());
5180 rData.NotifyFreeObj(pObj);
5183 void SvxMSDffManager::FreeObj(SvxMSDffClientData& rData, SdrObject* pObj)
5185 NotifyFreeObj(rData, pObj);
5188 rtl::Reference<SdrObject> SvxMSDffManager::ProcessObj(SvStream& rSt,
5189 DffObjData& rObjData,
5190 SvxMSDffClientData& rData,
5191 tools::Rectangle& rTextRect,
5192 SdrObject* pObj1
5195 rtl::Reference<SdrObject> pObj = pObj1;
5196 if( !rTextRect.IsEmpty() )
5198 SvxMSDffImportData& rImportData = static_cast<SvxMSDffImportData&>(rData);
5199 SvxMSDffImportRec* pImpRec = new SvxMSDffImportRec;
5200 bool bDeleteImpRec = true;
5201 SvxMSDffImportRec* pTextImpRec = pImpRec;
5202 bool bDeleteTextImpRec = false;
5204 // fill Import Record with data
5205 pImpRec->nShapeId = rObjData.nShapeId;
5206 pImpRec->eShapeType = rObjData.eShapeType;
5208 auto eWrapMode = GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare);
5209 rObjData.bClientAnchor = maShapeRecords.SeekToContent( rSt,
5210 DFF_msofbtClientAnchor,
5211 SEEK_FROM_CURRENT_AND_RESTART );
5212 if( rObjData.bClientAnchor )
5213 ProcessClientAnchor( rSt,
5214 maShapeRecords.Current()->nRecLen,
5215 pImpRec->pClientAnchorBuffer, pImpRec->nClientAnchorLen );
5217 rObjData.bClientData = maShapeRecords.SeekToContent( rSt,
5218 DFF_msofbtClientData,
5219 SEEK_FROM_CURRENT_AND_RESTART );
5220 if( rObjData.bClientData )
5221 ProcessClientData( rSt,
5222 maShapeRecords.Current()->nRecLen,
5223 pImpRec->pClientDataBuffer, pImpRec->nClientDataLen );
5226 // process user (== Winword) defined parameters in 0xF122 record
5227 if( maShapeRecords.SeekToContent( rSt,
5228 DFF_msofbtUDefProp,
5229 SEEK_FROM_CURRENT_AND_RESTART )
5230 && maShapeRecords.Current()->nRecLen )
5232 sal_uInt32 nBytesLeft = maShapeRecords.Current()->nRecLen;
5233 while( 5 < nBytesLeft )
5235 sal_uInt16 nPID(0);
5236 rSt.ReadUInt16(nPID);
5237 if (!rSt.good())
5238 break;
5239 sal_uInt32 nUDData(0);
5240 rSt.ReadUInt32(nUDData);
5241 switch (nPID)
5243 case 0x038F: pImpRec->nXAlign = nUDData; break;
5244 case 0x0390:
5245 pImpRec->nXRelTo = nUDData;
5246 break;
5247 case 0x0391: pImpRec->nYAlign = nUDData; break;
5248 case 0x0392:
5249 pImpRec->nYRelTo = nUDData;
5250 break;
5251 case 0x03BF: pImpRec->nGroupShapeBooleanProperties = nUDData; break;
5252 case 0x0393:
5253 // This seems to correspond to o:hrpct from .docx (even including
5254 // the difference that it's in 0.1% even though the .docx spec
5255 // says it's in 1%).
5256 pImpRec->relativeHorizontalWidth = nUDData;
5257 break;
5258 case 0x0394:
5259 // And this is really just a guess, but a mere presence of this
5260 // flag makes a horizontal rule be as wide as the page (unless
5261 // overridden by something), so it probably matches o:hr from .docx.
5262 pImpRec->isHorizontalRule = true;
5263 break;
5265 if (!rSt.good())
5266 break;
5267 nBytesLeft -= 6;
5271 // text frame, also Title or Outline
5272 rtl::Reference<SdrObject> pOrgObj = pObj;
5273 rtl::Reference<SdrRectObj> pTextObj;
5274 sal_uInt32 nTextId = GetPropertyValue( DFF_Prop_lTxid, 0 );
5275 if( nTextId )
5277 SfxItemSet aSet( pSdrModel->GetItemPool() );
5279 //Originally anything that as a mso_sptTextBox was created as a
5280 //textbox, this was changed for #88277# to be created as a simple
5281 //rect to keep impress happy. For the rest of us we'd like to turn
5282 //it back into a textbox again.
5283 bool bTextFrame = (pImpRec->eShapeType == mso_sptTextBox);
5284 if (!bTextFrame)
5286 //Either
5287 //a) it's a simple text object or
5288 //b) it's a rectangle with text and square wrapping.
5289 bTextFrame =
5291 (pImpRec->eShapeType == mso_sptTextSimple) ||
5293 (pImpRec->eShapeType == mso_sptRectangle)
5294 && (eWrapMode == mso_wrapSquare)
5295 && ShapeHasText(pImpRec->nShapeId, rObjData.rSpHd.GetRecBegFilePos() )
5300 if (bTextFrame)
5302 pObj = nullptr;
5303 pOrgObj = nullptr;
5306 // Distance of Textbox to its surrounding Customshape
5307 sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 91440L);
5308 sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 91440L );
5309 sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 45720L );
5310 sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 45720L );
5312 ScaleEmu( nTextLeft );
5313 ScaleEmu( nTextRight );
5314 ScaleEmu( nTextTop );
5315 ScaleEmu( nTextBottom );
5317 Degree100 nTextRotationAngle(0);
5318 bool bVerticalText = false;
5319 if ( IsProperty( DFF_Prop_txflTextFlow ) )
5321 auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF;
5322 switch( eTextFlow )
5324 case mso_txflBtoT:
5325 nTextRotationAngle = 9000_deg100;
5326 break;
5327 case mso_txflVertN:
5328 case mso_txflTtoBN:
5329 nTextRotationAngle = 27000_deg100;
5330 break;
5331 case mso_txflTtoBA:
5332 bVerticalText = true;
5333 break;
5334 case mso_txflHorzA:
5335 bVerticalText = true;
5336 nTextRotationAngle = 9000_deg100;
5337 break;
5338 case mso_txflHorzN:
5339 default :
5340 break;
5344 if (nTextRotationAngle)
5346 switch (nTextRotationAngle.get())
5348 case 9000:
5350 tools::Long nWidth = rTextRect.GetWidth();
5351 rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() );
5352 rTextRect.SetBottom( rTextRect.Top() + nWidth );
5354 sal_Int32 nOldTextLeft = nTextLeft;
5355 sal_Int32 nOldTextRight = nTextRight;
5356 sal_Int32 nOldTextTop = nTextTop;
5357 sal_Int32 nOldTextBottom = nTextBottom;
5359 nTextLeft = nOldTextBottom;
5360 nTextRight = nOldTextTop;
5361 nTextTop = nOldTextLeft;
5362 nTextBottom = nOldTextRight;
5364 break;
5365 case 27000:
5367 tools::Long nWidth = rTextRect.GetWidth();
5368 rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() );
5369 rTextRect.SetBottom( rTextRect.Top() + nWidth );
5371 sal_Int32 nOldTextLeft = nTextLeft;
5372 sal_Int32 nOldTextRight = nTextRight;
5373 sal_Int32 nOldTextTop = nTextTop;
5374 sal_Int32 nOldTextBottom = nTextBottom;
5376 nTextLeft = nOldTextTop;
5377 nTextRight = nOldTextBottom;
5378 nTextTop = nOldTextRight;
5379 nTextBottom = nOldTextLeft;
5381 break;
5385 pTextObj = new SdrRectObj(
5386 *pSdrModel,
5387 SdrObjKind::Text,
5388 rTextRect);
5389 pTextImpRec = new SvxMSDffImportRec(*pImpRec);
5390 bDeleteTextImpRec = true;
5392 // the vertical paragraph indents are part of the BoundRect,
5393 // here we 'remove' them by calculating
5394 tools::Rectangle aNewRect(rTextRect);
5395 aNewRect.AdjustBottom( -(nTextTop + nTextBottom) );
5396 aNewRect.AdjustRight( -(nTextLeft + nTextRight) );
5398 // Only if it's a simple textbox may Writer replace
5399 // the object with a frame, otherwise
5400 if( bTextFrame )
5402 auto const pTmpRec = std::make_shared<SvxMSDffShapeInfo>(0, pImpRec->nShapeId);
5404 SvxMSDffShapeInfos_ById::const_iterator const it =
5405 m_xShapeInfosById->find(pTmpRec);
5406 if (it != m_xShapeInfosById->end())
5408 SvxMSDffShapeInfo& rInfo = **it;
5409 pTextImpRec->bReplaceByFly = rInfo.bReplaceByFly;
5413 if( !pObj )
5414 ApplyAttributes( rSt, aSet, rObjData );
5416 bool bFitText = false;
5417 if (GetPropertyValue(DFF_Prop_FitTextToShape, 0) & 2)
5419 aSet.Put( makeSdrTextAutoGrowHeightItem( true ) );
5420 aSet.Put( makeSdrTextMinFrameHeightItem(
5421 aNewRect.Bottom() - aNewRect.Top() ) );
5422 aSet.Put( makeSdrTextMinFrameWidthItem(
5423 aNewRect.Right() - aNewRect.Left() ) );
5424 bFitText = true;
5426 else
5428 aSet.Put( makeSdrTextAutoGrowHeightItem( false ) );
5429 aSet.Put( makeSdrTextAutoGrowWidthItem( false ) );
5432 switch (GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare))
5434 case mso_wrapNone :
5435 aSet.Put( makeSdrTextAutoGrowWidthItem( true ) );
5436 if (bFitText)
5438 //can't do autowidth in flys #i107184#
5439 pTextImpRec->bReplaceByFly = false;
5441 break;
5442 case mso_wrapByPoints :
5443 aSet.Put( makeSdrTextContourFrameItem( true ) );
5444 break;
5445 default: break;
5448 // set margins at the border of the textbox
5449 aSet.Put( makeSdrTextLeftDistItem( nTextLeft ) );
5450 aSet.Put( makeSdrTextRightDistItem( nTextRight ) );
5451 aSet.Put( makeSdrTextUpperDistItem( nTextTop ) );
5452 aSet.Put( makeSdrTextLowerDistItem( nTextBottom ) );
5453 pTextImpRec->nDxTextLeft = nTextLeft;
5454 pTextImpRec->nDyTextTop = nTextTop;
5455 pTextImpRec->nDxTextRight = nTextRight;
5456 pTextImpRec->nDyTextBottom = nTextBottom;
5458 // read text anchor
5459 if ( IsProperty( DFF_Prop_anchorText ) )
5461 auto eTextAnchor = GetPropertyValue(DFF_Prop_anchorText, 0);
5463 SdrTextVertAdjust eTVA = SDRTEXTVERTADJUST_CENTER;
5464 bool bTVASet(false);
5465 bool bTHASet(false);
5467 switch( eTextAnchor )
5469 case mso_anchorTop:
5471 eTVA = SDRTEXTVERTADJUST_TOP;
5472 bTVASet = true;
5474 break;
5475 case mso_anchorTopCentered:
5477 eTVA = SDRTEXTVERTADJUST_TOP;
5478 bTVASet = true;
5479 bTHASet = true;
5481 break;
5483 case mso_anchorMiddle:
5484 bTVASet = true;
5485 break;
5486 case mso_anchorMiddleCentered:
5488 bTVASet = true;
5489 bTHASet = true;
5491 break;
5492 case mso_anchorBottom:
5494 eTVA = SDRTEXTVERTADJUST_BOTTOM;
5495 bTVASet = true;
5497 break;
5498 case mso_anchorBottomCentered:
5500 eTVA = SDRTEXTVERTADJUST_BOTTOM;
5501 bTVASet = true;
5502 bTHASet = true;
5504 break;
5505 default : break;
5507 // insert
5508 if ( bTVASet )
5509 aSet.Put( SdrTextVertAdjustItem( eTVA ) );
5510 if ( bTHASet )
5511 aSet.Put( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_CENTER ) );
5514 pTextObj->SetMergedItemSet(aSet);
5516 if (bVerticalText)
5517 pTextObj->SetVerticalWriting(true);
5519 if (nTextRotationAngle)
5521 tools::Long nMinWH = rTextRect.GetWidth() < rTextRect.GetHeight() ?
5522 rTextRect.GetWidth() : rTextRect.GetHeight();
5523 nMinWH /= 2;
5524 Point aPivot(rTextRect.TopLeft());
5525 aPivot.AdjustX(nMinWH );
5526 aPivot.AdjustY(nMinWH );
5527 pTextObj->SdrAttrObj::NbcRotate(aPivot, nTextRotationAngle);
5530 // rotate text with shape?
5531 if ( mnFix16Angle )
5533 double a = toRadians(mnFix16Angle);
5534 pTextObj->NbcRotate( rObjData.aBoundRect.Center(), mnFix16Angle,
5535 sin( a ), cos( a ) );
5538 if( !pObj )
5540 pObj = pTextObj.get();
5542 else
5544 if( pTextObj.get() != pObj.get() )
5546 rtl::Reference<SdrObject> pGroup = new SdrObjGroup(*pSdrModel);
5547 pGroup->GetSubList()->NbcInsertObject( pObj.get() );
5548 pGroup->GetSubList()->NbcInsertObject( pTextObj.get() );
5549 if (pOrgObj == pObj)
5550 pOrgObj = pGroup;
5551 else
5552 pOrgObj = pObj;
5553 pObj = pGroup.get();
5557 else if( !pObj )
5559 // simple rectangular objects are ignored by ImportObj() :-(
5560 // this is OK for Draw but not for Calc and Writer
5561 // cause here these objects have a default border
5562 pObj = new SdrRectObj(
5563 *pSdrModel,
5564 rTextRect);
5566 pOrgObj = pObj;
5567 SfxItemSet aSet( pSdrModel->GetItemPool() );
5568 ApplyAttributes( rSt, aSet, rObjData );
5570 SfxItemState eState = aSet.GetItemState( XATTR_FILLCOLOR );
5571 if( SfxItemState::DEFAULT == eState )
5572 aSet.Put( XFillColorItem( OUString(), mnDefaultColor ) );
5573 pObj->SetMergedItemSet(aSet);
5576 //Means that fBehindDocument is set
5577 if (GetPropertyValue(DFF_Prop_fPrint, 0) & 0x20)
5578 pImpRec->bDrawHell = true;
5579 else
5580 pImpRec->bDrawHell = false;
5581 if (GetPropertyValue(DFF_Prop_fPrint, 0) & 0x02)
5582 pImpRec->bHidden = true;
5583 pTextImpRec->bDrawHell = pImpRec->bDrawHell;
5584 pTextImpRec->bHidden = pImpRec->bHidden;
5585 pImpRec->nNextShapeId = GetPropertyValue( DFF_Prop_hspNext, 0 );
5586 pTextImpRec->nNextShapeId=pImpRec->nNextShapeId;
5588 if ( nTextId )
5590 pTextImpRec->aTextId.nTxBxS = static_cast<sal_uInt16>( nTextId >> 16 );
5591 pTextImpRec->aTextId.nSequence = static_cast<sal_uInt16>(nTextId);
5594 pTextImpRec->nDxWrapDistLeft = GetPropertyValue(
5595 DFF_Prop_dxWrapDistLeft, 114935L ) / 635L;
5596 pTextImpRec->nDyWrapDistTop = GetPropertyValue(
5597 DFF_Prop_dyWrapDistTop, 0 ) / 635L;
5598 pTextImpRec->nDxWrapDistRight = GetPropertyValue(
5599 DFF_Prop_dxWrapDistRight, 114935L ) / 635L;
5600 pTextImpRec->nDyWrapDistBottom = GetPropertyValue(
5601 DFF_Prop_dyWrapDistBottom, 0 ) / 635L;
5602 // 16.16 fraction times total image width or height, as appropriate.
5604 if (SeekToContent(DFF_Prop_pWrapPolygonVertices, rSt))
5606 pTextImpRec->pWrapPolygon.reset();
5607 sal_uInt16 nNumElemVert(0), nNumElemMemVert(0), nElemSizeVert(8);
5608 rSt.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert );
5609 // If this value is 0xFFF0 then this record is an array of truncated 8 byte elements. Only the 4
5610 // low-order bytes are recorded
5611 if (nElemSizeVert == 0xFFF0)
5612 nElemSizeVert = 4;
5614 // sanity check that the stream is long enough to fulfill nNumElemVert * nElemSizeVert;
5615 bool bOk = nElemSizeVert && (rSt.remainingSize() / nElemSizeVert >= nNumElemVert);
5616 if (bOk)
5618 pTextImpRec->pWrapPolygon = tools::Polygon(nNumElemVert);
5619 for (sal_uInt16 i = 0; i < nNumElemVert; ++i)
5621 sal_Int32 nX(0), nY(0);
5622 if (nElemSizeVert == 8)
5623 rSt.ReadInt32( nX ).ReadInt32( nY );
5624 else
5626 sal_Int16 nSmallX(0), nSmallY(0);
5627 rSt.ReadInt16( nSmallX ).ReadInt16( nSmallY );
5628 nX = nSmallX;
5629 nY = nSmallY;
5631 (*(pTextImpRec->pWrapPolygon))[i].setX( nX );
5632 (*(pTextImpRec->pWrapPolygon))[i].setY( nY );
5637 pImpRec->nCropFromTop = GetPropertyValue(
5638 DFF_Prop_cropFromTop, 0 );
5639 pImpRec->nCropFromBottom = GetPropertyValue(
5640 DFF_Prop_cropFromBottom, 0 );
5641 pImpRec->nCropFromLeft = GetPropertyValue(
5642 DFF_Prop_cropFromLeft, 0 );
5643 pImpRec->nCropFromRight = GetPropertyValue(
5644 DFF_Prop_cropFromRight, 0 );
5646 pImpRec->bVFlip = bool(rObjData.nSpFlags & ShapeFlag::FlipV);
5647 pImpRec->bHFlip = bool(rObjData.nSpFlags & ShapeFlag::FlipH);
5649 sal_uInt32 nLineFlags = GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 );
5650 pImpRec->eLineStyle = (nLineFlags & 8)
5651 ? static_cast<MSO_LineStyle>(GetPropertyValue(
5652 DFF_Prop_lineStyle,
5653 mso_lineSimple ))
5654 : MSO_LineStyle_NONE;
5655 pTextImpRec->eLineStyle = pImpRec->eLineStyle;
5657 pImpRec->eLineDashing = static_cast<MSO_LineDashing>(GetPropertyValue(
5658 DFF_Prop_lineDashing, mso_lineSolid ));
5659 pTextImpRec->eLineDashing = pImpRec->eLineDashing;
5661 if( pImpRec->nShapeId )
5663 // amend the import record list
5664 if( pOrgObj )
5666 pImpRec->pObj = pOrgObj.get();
5667 rImportData.insert(std::unique_ptr<SvxMSDffImportRec>(pImpRec));
5668 bDeleteImpRec = false;
5669 if (pImpRec == pTextImpRec)
5670 bDeleteTextImpRec = false;
5673 if( pTextObj && (pOrgObj != pTextObj) )
5675 // Modify ShapeId (must be unique)
5676 pImpRec->nShapeId |= 0x8000000;
5677 pTextImpRec->pObj = pTextObj.get();
5678 rImportData.insert(std::unique_ptr<SvxMSDffImportRec>(pTextImpRec));
5679 bDeleteTextImpRec = false;
5680 if (pTextImpRec == pImpRec)
5681 bDeleteImpRec = false;
5684 // entry in the z-order-list in order to complement the pointer to this object
5685 /*Only store objects which are not deep inside the tree*/
5686 if( ( rObjData.nCalledByGroup == 0 )
5688 ( (rObjData.nSpFlags & ShapeFlag::Group)
5689 && (rObjData.nCalledByGroup < 2) )
5691 StoreShapeOrder( pImpRec->nShapeId,
5692 ( static_cast<sal_uLong>(pImpRec->aTextId.nTxBxS) << 16 )
5693 + pImpRec->aTextId.nSequence, pObj.get() );
5696 if (bDeleteImpRec)
5697 delete pImpRec;
5699 if (bDeleteTextImpRec)
5700 delete pTextImpRec;
5703 return pObj;
5706 SdrObject* SvxMSDffManager::FinalizeObj(DffObjData& /* rObjData */, SdrObject* pObj)
5708 return pObj;
5712 void SvxMSDffManager::StoreShapeOrder(sal_uLong nId,
5713 sal_uLong nTxBx,
5714 SdrObject* pObject,
5715 SwFlyFrameFormat* pFly) const
5717 for (const auto& pOrder : m_aShapeOrders)
5719 if (pOrder->nShapeId == nId)
5721 pOrder->nTxBxComp = nTxBx;
5722 pOrder->pObj = pObject;
5723 pOrder->pFly = pFly;
5729 void SvxMSDffManager::ExchangeInShapeOrder( SdrObject const * pOldObject,
5730 sal_uLong nTxBx,
5731 SdrObject* pObject) const
5733 for (const auto& pOrder : m_aShapeOrders)
5735 if (pOrder->pObj == pOldObject)
5737 pOrder->pFly = nullptr;
5738 pOrder->pObj = pObject;
5739 pOrder->nTxBxComp = nTxBx;
5745 void SvxMSDffManager::RemoveFromShapeOrder( SdrObject const * pObject ) const
5747 for (const auto& pOrder : m_aShapeOrders)
5749 if (pOrder->pObj == pObject)
5751 pOrder->pObj = nullptr;
5752 pOrder->pFly = nullptr;
5753 pOrder->nTxBxComp = 0;
5759 // exported class: Public Methods
5761 SvxMSDffManager::SvxMSDffManager(SvStream& rStCtrl_,
5762 OUString aBaseURL,
5763 sal_uInt32 nOffsDgg_,
5764 SvStream* pStData_,
5765 SdrModel* pSdrModel_,// see SetModel() below
5766 tools::Long nApplicationScale,
5767 Color mnDefaultColor_,
5768 SvStream* pStData2_,
5769 bool bSkipImages )
5770 :DffPropertyReader( *this ),
5771 m_pBLIPInfos( new SvxMSDffBLIPInfos ),
5772 m_xShapeInfosByTxBxComp( new SvxMSDffShapeInfos_ByTxBxComp ),
5773 nOffsDgg( nOffsDgg_ ),
5774 nBLIPCount( USHRT_MAX ), // initialize with error, since we first check if the
5775 nGroupShapeFlags(ShapeFlag::NONE), // ensure initialization here, as some corrupted
5776 // files may yield to this being uninitialized
5777 maBaseURL(std::move( aBaseURL )),
5778 mnIdClusters(0),
5779 rStCtrl( rStCtrl_ ),
5780 pStData( pStData_ ),
5781 pStData2( pStData2_ ),
5782 nSvxMSDffSettings( 0 ),
5783 nSvxMSDffOLEConvFlags( 0 ),
5784 mnDefaultColor( mnDefaultColor_),
5785 mbSkipImages (bSkipImages)
5787 SetModel( pSdrModel_, nApplicationScale );
5789 // remember FilePos of the stream(s)
5790 sal_uInt64 nOldPosCtrl = rStCtrl.Tell();
5791 sal_uInt64 nOldPosData = pStData ? pStData->Tell() : nOldPosCtrl;
5793 // if no data stream is given we assume that the BLIPs
5794 // are in the control stream
5795 if( !pStData )
5796 pStData = &rStCtrl;
5798 SetDefaultPropSet( rStCtrl, nOffsDgg );
5800 // read control stream, if successful set nBLIPCount
5801 GetCtrlData( nOffsDgg );
5803 // check Text-Box-Story-Chain-Infos
5804 CheckTxBxStoryChain();
5806 // restore old FilePos of the stream(s)
5807 rStCtrl.Seek( nOldPosCtrl );
5808 if( &rStCtrl != pStData )
5809 pStData->Seek( nOldPosData );
5812 SvxMSDffManager::SvxMSDffManager( SvStream& rStCtrl_, OUString aBaseURL )
5813 :DffPropertyReader( *this ),
5814 m_pBLIPInfos( new SvxMSDffBLIPInfos ),
5815 m_xShapeInfosByTxBxComp( new SvxMSDffShapeInfos_ByTxBxComp ),
5816 nOffsDgg( 0 ),
5817 nBLIPCount( USHRT_MAX ), // initialize with error, since we first have to check
5818 nGroupShapeFlags(ShapeFlag::NONE),
5819 maBaseURL(std::move( aBaseURL )),
5820 mnIdClusters(0),
5821 rStCtrl( rStCtrl_ ),
5822 pStData( nullptr ),
5823 pStData2( nullptr ),
5824 nSvxMSDffSettings( 0 ),
5825 nSvxMSDffOLEConvFlags( 0 ),
5826 mnDefaultColor( COL_DEFAULT ),
5827 mbSkipImages(false)
5829 SetModel( nullptr, 0 );
5832 SvxMSDffManager::~SvxMSDffManager()
5836 void SvxMSDffManager::InitSvxMSDffManager( sal_uInt32 nOffsDgg_, SvStream* pStData_, sal_uInt32 nOleConvFlags )
5838 nOffsDgg = nOffsDgg_;
5839 pStData = pStData_;
5840 nSvxMSDffOLEConvFlags = nOleConvFlags;
5842 // remember FilePos of the stream(s)
5843 sal_uInt64 nOldPosCtrl = rStCtrl.Tell();
5845 SetDefaultPropSet( rStCtrl, nOffsDgg );
5847 // insert fidcl cluster table
5848 GetFidclData( nOffsDgg );
5850 // read control stream, if successful, set nBLIPCount
5851 GetCtrlData( nOffsDgg );
5853 // check Text-Box-Story-Chain-Infos
5854 CheckTxBxStoryChain();
5856 // restore old FilePos of the stream(s)
5857 rStCtrl.Seek( nOldPosCtrl );
5860 void SvxMSDffManager::SetDgContainer( SvStream& rSt )
5862 sal_uInt64 nFilePos = rSt.Tell();
5863 DffRecordHeader aDgContHd;
5864 bool bOk = ReadDffRecordHeader(rSt, aDgContHd);
5865 // insert this container only if there is also a DggAtom
5866 if (bOk && SeekToRec(rSt, DFF_msofbtDg, aDgContHd.GetRecEndFilePos()))
5868 DffRecordHeader aRecHd;
5869 if (ReadDffRecordHeader(rSt, aRecHd))
5871 sal_uInt32 nDrawingId = aRecHd.nRecInstance;
5872 maDgOffsetTable[nDrawingId] = nFilePos;
5875 rSt.Seek(nFilePos);
5878 void SvxMSDffManager::GetFidclData( sal_uInt32 nOffsDggL )
5880 if (!nOffsDggL)
5881 return;
5883 sal_uInt64 nOldPos = rStCtrl.Tell();
5885 if (nOffsDggL == rStCtrl.Seek(nOffsDggL))
5887 DffRecordHeader aRecHd;
5888 bool bOk = ReadDffRecordHeader(rStCtrl, aRecHd);
5890 DffRecordHeader aDggAtomHd;
5891 if (bOk && SeekToRec(rStCtrl, DFF_msofbtDgg, aRecHd.GetRecEndFilePos(), &aDggAtomHd))
5893 aDggAtomHd.SeekToContent( rStCtrl );
5894 sal_uInt32 nCurMaxShapeId;
5895 sal_uInt32 nDummy;
5896 rStCtrl.ReadUInt32( nCurMaxShapeId )
5897 .ReadUInt32( mnIdClusters )
5898 .ReadUInt32( nDummy )
5899 .ReadUInt32( nDummy ); // nDrawingsSaved
5901 if ( mnIdClusters-- > 2 )
5903 const std::size_t nFIDCLsize = sizeof(sal_uInt32) * 2;
5904 if ( aDggAtomHd.nRecLen == ( mnIdClusters * nFIDCLsize + 16 ) )
5906 sal_uInt64 nMaxEntriesPossible = rStCtrl.remainingSize() / nFIDCLsize;
5907 SAL_WARN_IF(nMaxEntriesPossible < mnIdClusters,
5908 "filter.ms", "FIDCL list longer than remaining bytes, ppt or parser is wrong");
5909 mnIdClusters = std::min(nMaxEntriesPossible, static_cast<sal_uInt64>(mnIdClusters));
5911 maFidcls.resize(mnIdClusters);
5912 for (sal_uInt32 i = 0; i < mnIdClusters; ++i)
5914 sal_uInt32 cspidCur; ///< number of SPIDs used so far
5915 rStCtrl.ReadUInt32( maFidcls[ i ].dgid )
5916 .ReadUInt32( cspidCur );
5922 rStCtrl.Seek( nOldPos );
5925 void SvxMSDffManager::CheckTxBxStoryChain()
5927 m_xShapeInfosById.reset(new SvxMSDffShapeInfos_ById);
5928 // mangle old Info array, sorted by nTxBxComp
5929 sal_uInt32 nChain = std::numeric_limits<sal_uInt32>::max();
5930 bool bSetReplaceFALSE = false;
5931 for (SvxMSDffShapeInfos_ByTxBxComp::iterator iter =
5932 m_xShapeInfosByTxBxComp->begin(),
5933 mark = m_xShapeInfosByTxBxComp->begin();
5934 iter != m_xShapeInfosByTxBxComp->end(); ++iter)
5936 std::shared_ptr<SvxMSDffShapeInfo> const& pObj = *iter;
5937 if( pObj->nTxBxComp )
5939 // group change?
5940 // the text id also contains an internal drawing container id
5941 // to distinguish between text id of drawing objects in different
5942 // drawing containers.
5943 if( nChain != pObj->nTxBxComp )
5945 // reset mark and helper flag
5946 mark = iter;
5947 nChain = pObj->nTxBxComp;
5948 bSetReplaceFALSE = !pObj->bReplaceByFly;
5950 else if( !pObj->bReplaceByFly )
5952 // object that must NOT be replaced by frame?
5953 bSetReplaceFALSE = true;
5954 // maybe reset flags in start of group
5955 for (SvxMSDffShapeInfos_ByTxBxComp::iterator itemp = mark;
5956 itemp != iter; ++itemp)
5958 (*itemp)->bReplaceByFly = false;
5962 if( bSetReplaceFALSE )
5964 pObj->bReplaceByFly = false;
5967 // copy all Shape Info objects to m_xShapeInfosById, sorted by nShapeId
5968 pObj->nTxBxComp = pObj->nTxBxComp & 0xFFFF0000;
5969 m_xShapeInfosById->insert( pObj );
5971 // free original array but don't free its elements
5972 m_xShapeInfosByTxBxComp.reset();
5976 /*****************************************************************************
5978 Reading the Shape-Infos in the Ctor:
5979 ---------------------------------
5980 remembering the Shape-Ids and the associated Blip-Numbers and TextBox-Infos
5981 ========= ============ =============
5982 and remembering the File-Offsets for each Blip
5983 ============
5984 ******************************************************************************/
5985 void SvxMSDffManager::GetCtrlData(sal_uInt32 nOffsDggL)
5987 // position control stream
5988 if (!checkSeek(rStCtrl, nOffsDggL))
5989 return;
5991 sal_uInt8 nVer(0);
5992 sal_uInt16 nInst(0);
5993 sal_uInt16 nFbt(0);
5994 sal_uInt32 nLength(0);
5995 if( !ReadCommonRecordHeader( rStCtrl, nVer, nInst, nFbt, nLength ) ) return;
5997 sal_uInt64 nPos = nOffsDggL + DFF_COMMON_RECORD_HEADER_SIZE;
5999 // case A: first Drawing Group Container, then n times Drawing Container
6000 if( DFF_msofbtDggContainer != nFbt )
6001 return;
6003 bool bOk;
6004 GetDrawingGroupContainerData( rStCtrl, nLength );
6006 sal_uInt64 nMaxStrPos = rStCtrl.TellEnd();
6008 nPos += nLength;
6009 sal_uInt16 nDrawingContainerId = 1;
6012 if (!checkSeek(rStCtrl, nPos))
6013 break;
6015 bOk = ReadCommonRecordHeader( rStCtrl, nVer, nInst, nFbt, nLength ) && ( DFF_msofbtDgContainer == nFbt );
6017 if( !bOk )
6019 nPos++; // ????????? TODO: trying to get a one-hit wonder, this code should be rewritten...
6020 if (nPos != rStCtrl.Seek(nPos))
6021 break;
6022 bOk = ReadCommonRecordHeader( rStCtrl, nVer, nInst, nFbt, nLength )
6023 && ( DFF_msofbtDgContainer == nFbt );
6025 if( bOk )
6027 GetDrawingContainerData( rStCtrl, nLength, nDrawingContainerId );
6029 nPos += DFF_COMMON_RECORD_HEADER_SIZE + nLength;
6030 ++nDrawingContainerId;
6032 while( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( nPos < nMaxStrPos ) && bOk );
6036 // from here on: Drawing Group Container i.e. document-wide valid data
6038 void SvxMSDffManager::GetDrawingGroupContainerData( SvStream& rSt, sal_uInt32 nLenDgg )
6040 sal_uInt8 nVer;
6041 sal_uInt16 nInst;
6042 sal_uInt16 nFbt;
6043 sal_uInt32 nLength;
6045 sal_uInt32 nLenBStoreCont = 0, nLenFBSE = 0;
6046 sal_uLong nRead = 0;
6048 // search for a BStore Container
6049 bool bOk = true;
6052 if (!ReadCommonRecordHeader(rSt, nVer, nInst, nFbt, nLength))
6053 return;
6054 nRead += DFF_COMMON_RECORD_HEADER_SIZE + nLength;
6055 if (DFF_msofbtBstoreContainer == nFbt)
6057 nLenBStoreCont = nLength;
6058 break;
6060 bOk = checkSeek(rSt, rSt.Tell() + nLength);
6062 while (bOk && nRead < nLenDgg);
6064 if (!bOk || !nLenBStoreCont)
6065 return;
6067 // Read all atoms of the containers from the BStore container and store all
6068 // relevant data of all contained FBSEs in out pointer array.
6069 // We also count all found FBSEs in member nBLIPCount.
6071 const sal_uInt8 nSkipBLIPLen = 20; // skip to get to the nBLIPLen
6072 const sal_uInt8 nSkipBLIPPos = 4; // thereafter skip up to nBLIPPos
6074 sal_uInt32 nBLIPLen = 0, nBLIPPos = 0;
6076 nRead = 0;
6079 if(!ReadCommonRecordHeader( rSt, nVer, nInst, nFbt, nLength)) return;
6080 nRead += DFF_COMMON_RECORD_HEADER_SIZE + nLength;
6081 if( DFF_msofbtBSE == nFbt && /* magic value from spec */ 0x2 == nVer )
6083 nLenFBSE = nLength;
6084 // is FBSE big enough for our data
6085 bOk = ( nSkipBLIPLen + 4 + nSkipBLIPPos + 4 <= nLenFBSE );
6087 if (bOk)
6089 rSt.SeekRel( nSkipBLIPLen );
6090 rSt.ReadUInt32( nBLIPLen );
6091 rSt.SeekRel( nSkipBLIPPos );
6092 rSt.ReadUInt32( nBLIPPos );
6093 bOk = rSt.GetError() == ERRCODE_NONE;
6095 nLength -= nSkipBLIPLen+ 4 + nSkipBLIPPos + 4;
6098 if (bOk)
6100 // specialty:
6101 // If nBLIPLen is less than nLenFBSE AND nBLIPPos is NULL,
6102 // then we assume, that the image is in FBSE!
6103 if( (!nBLIPPos) && (nBLIPLen < nLenFBSE) )
6104 nBLIPPos = rSt.Tell() + 4;
6106 if( USHRT_MAX == nBLIPCount )
6107 nBLIPCount = 1;
6108 else
6109 nBLIPCount++;
6111 // now save the info for later access
6112 m_pBLIPInfos->push_back(SvxMSDffBLIPInfo(nBLIPPos));
6114 if (!checkSeek(rSt, rSt.Tell() + nLength))
6115 return; // invalid offset
6117 else return; // invalid input
6119 while( nRead < nLenBStoreCont );
6123 // from now on: Drawing Container which means Pages (Sheet, Slide) - wide valid data
6124 // ================= ======
6126 void SvxMSDffManager::GetDrawingContainerData( SvStream& rSt, sal_uInt32 nLenDg,
6127 sal_uInt16 nDrawingContainerId )
6129 sal_uInt8 nVer;sal_uInt16 nInst;sal_uInt16 nFbt(0);sal_uInt32 nLength(0);
6131 sal_uLong nReadDg = 0;
6133 // We are now in a drawing container (one per each page) and
6134 // we now have to iterate through all contained shape group containers
6137 if (!ReadCommonRecordHeader(rSt, nVer, nInst, nFbt, nLength))
6138 return;
6139 nReadDg += DFF_COMMON_RECORD_HEADER_SIZE;
6140 // Patriarch found (the upmost shape group container) ?
6141 if (DFF_msofbtSpgrContainer == nFbt)
6143 if (!GetShapeGroupContainerData(rSt, nLength, true, nDrawingContainerId))
6144 return;
6146 // empty Shape Container ? (outside of shape group container)
6147 else if (DFF_msofbtSpContainer == nFbt)
6149 if (!GetShapeContainerData(
6150 rSt, nLength, std::numeric_limits<sal_uInt64>::max(), nDrawingContainerId))
6151 return;
6153 else
6155 if (!checkSeek(rSt, rSt.Tell() + nLength))
6156 return;
6158 nReadDg += nLength;
6160 while( nReadDg < nLenDg );
6163 bool SvxMSDffManager::GetShapeGroupContainerData( SvStream& rSt,
6164 sal_uInt32 nLenShapeGroupCont,
6165 bool bPatriarch,
6166 sal_uInt16 nDrawingContainerId )
6168 sal_uInt8 nVer;sal_uInt16 nInst;sal_uInt16 nFbt;sal_uInt32 nLength;
6169 sal_uInt64 nStartShapeGroupCont = rSt.Tell();
6170 // We are now in a shape group container (conditionally multiple per page)
6171 // and we now have to iterate through all contained shape containers
6172 bool bFirst = !bPatriarch;
6173 sal_uLong nReadSpGrCont = 0;
6176 if( !ReadCommonRecordHeader( rSt, nVer, nInst, nFbt, nLength ) )
6177 return false;
6178 nReadSpGrCont += DFF_COMMON_RECORD_HEADER_SIZE;
6179 // Shape Container?
6180 if( DFF_msofbtSpContainer == nFbt )
6182 sal_uInt64 nGroupOffs = bFirst ? nStartShapeGroupCont - DFF_COMMON_RECORD_HEADER_SIZE : std::numeric_limits<sal_uInt64>::max();
6183 if ( !GetShapeContainerData( rSt, nLength, nGroupOffs, nDrawingContainerId ) )
6184 return false;
6185 bFirst = false;
6187 // nested shape group container ?
6188 else if( DFF_msofbtSpgrContainer == nFbt )
6190 if ( !GetShapeGroupContainerData( rSt, nLength, false, nDrawingContainerId ) )
6191 return false;
6193 else
6195 if (!checkSeek(rSt, rSt.Tell() + nLength))
6196 return false;
6198 nReadSpGrCont += nLength;
6200 while( nReadSpGrCont < nLenShapeGroupCont );
6201 // position the stream correctly
6202 rSt.Seek( nStartShapeGroupCont + nLenShapeGroupCont );
6203 return true;
6206 bool SvxMSDffManager::GetShapeContainerData( SvStream& rSt,
6207 sal_uInt32 nLenShapeCont,
6208 sal_uInt64 nPosGroup,
6209 sal_uInt16 nDrawingContainerId )
6211 sal_uInt8 nVer;sal_uInt16 nInst;sal_uInt16 nFbt;sal_uInt32 nLength;
6212 sal_uInt64 nStartShapeCont = rSt.Tell();
6214 // We are in a shape container (possibly more than one per shape group) and we now
6215 // have to fetch the shape id and file position (to be able to access them again later)
6216 // and the first BStore reference (if present).
6217 sal_uInt32 nLenShapePropTbl = 0;
6218 sal_uLong nReadSpCont = 0;
6220 // Store file offset of the shape containers or respectively the group(!).
6221 sal_uInt64 nStartOffs = (std::numeric_limits<sal_uInt64>::max() > nPosGroup) ?
6222 nPosGroup : nStartShapeCont - DFF_COMMON_RECORD_HEADER_SIZE;
6223 SvxMSDffShapeInfo aInfo( nStartOffs );
6225 // Can the shape be replaced with a frame?
6226 // (provided that it is a TextBox and the text is not rotated)
6227 bool bCanBeReplaced = nPosGroup >= std::numeric_limits<sal_uInt64>::max();
6229 // we don't know yet whether it's a TextBox
6230 MSO_SPT eShapeType = mso_sptNil;
6232 // analyze Shape
6236 if(!ReadCommonRecordHeader( rSt, nVer, nInst, nFbt, nLength)) return false;
6237 nReadSpCont += DFF_COMMON_RECORD_HEADER_SIZE;
6238 // FSP ?
6239 if( ( DFF_msofbtSp == nFbt ) && ( 4 <= nLength ) )
6241 // we've found the FSP: note Shape Type and Id!
6242 eShapeType = static_cast<MSO_SPT>(nInst);
6243 rSt.ReadUInt32( aInfo.nShapeId );
6244 rSt.SeekRel( nLength - 4 );
6245 nReadSpCont += nLength;
6247 else if( DFF_msofbtOPT == nFbt ) // Shape Property Table ?
6249 // We've found the Property Table:
6250 // search for the Blip Property!
6251 sal_uLong nPropRead = 0;
6252 nLenShapePropTbl = nLength;
6253 auto nStartShapePropTbl = rSt.Tell();
6256 sal_uInt16 nPropId(0);
6257 sal_uInt32 nPropVal(0);
6259 rSt.ReadUInt16( nPropId )
6260 .ReadUInt32( nPropVal );
6261 nPropRead += 6;
6263 switch( nPropId )
6265 case DFF_Prop_txflTextFlow :
6266 //Writer can now handle vertical textflows in its
6267 //native frames, to only need to do this for the
6268 //other two formats
6270 //Writer will handle all textflow except BtoT
6271 if (GetSvxMSDffSettings() &
6272 (SVXMSDFF_SETTINGS_IMPORT_PPT |
6273 SVXMSDFF_SETTINGS_IMPORT_EXCEL))
6275 if( 0 != nPropVal )
6276 bCanBeReplaced = false;
6278 else if (
6279 (nPropVal != mso_txflHorzN) &&
6280 (nPropVal != mso_txflTtoBA)
6283 bCanBeReplaced = false;
6285 break;
6286 case DFF_Prop_cdirFont :
6287 //Writer can now handle right to left and left
6288 //to right in its native frames, so only do
6289 //this for the other two formats.
6290 if (GetSvxMSDffSettings() &
6291 (SVXMSDFF_SETTINGS_IMPORT_PPT |
6292 SVXMSDFF_SETTINGS_IMPORT_EXCEL))
6294 if( 0 != nPropVal )
6295 bCanBeReplaced = false;
6297 break;
6298 case DFF_Prop_Rotation :
6299 if( 0 != nPropVal )
6300 bCanBeReplaced = false;
6301 break;
6303 case DFF_Prop_gtextFStrikethrough :
6304 if( ( 0x20002000 & nPropVal ) == 0x20002000 )
6305 bCanBeReplaced = false;
6306 break;
6308 case DFF_Prop_fc3DLightFace :
6309 if( ( 0x00080008 & nPropVal ) == 0x00080008 )
6310 bCanBeReplaced = false;
6311 break;
6313 case DFF_Prop_WrapText :
6314 //TODO: eWrapMode = (MSO_WrapMode)nPropVal;
6315 break;
6317 default:
6319 // is the Bit set and valid?
6320 if( 0x4000 == ( nPropId & 0xC000 ) )
6322 // Blip Property found: remember BStore Idx!
6323 nPropRead = nLenShapePropTbl;
6325 else if( 0x8000 & nPropId )
6327 // complex Prop found:
6328 // Length is always 6. The length of the appended extra data
6329 // after the actual prop table is of different size.
6332 break;
6335 while (rSt.good() && nPropRead < nLenShapePropTbl);
6336 rSt.Seek( nStartShapePropTbl + nLenShapePropTbl );
6337 nReadSpCont += nLenShapePropTbl;
6339 else if( ( DFF_msofbtClientTextbox == nFbt ) && ( 4 == nLength ) ) // Text-Box-Story-Entry found
6341 rSt.ReadUInt32( aInfo.nTxBxComp );
6342 // Add internal drawing container id to text id.
6343 // Note: The text id uses the first two bytes, while the internal
6344 // drawing container id used the second two bytes.
6345 aInfo.nTxBxComp = ( aInfo.nTxBxComp & 0xFFFF0000 ) +
6346 nDrawingContainerId;
6347 DBG_ASSERT( (aInfo.nTxBxComp & 0x0000FFFF) == nDrawingContainerId,
6348 "<SvxMSDffManager::GetShapeContainerData(..)> - internal drawing container Id could not be correctly merged into DFF_msofbtClientTextbox value." );
6350 else
6352 if (!checkSeek(rSt, rSt.Tell() + nLength))
6354 SAL_WARN("filter.ms", "remaining record longer than available data, ppt or parser is wrong");
6355 break;
6357 nReadSpCont += nLength;
6360 while( nReadSpCont < nLenShapeCont );
6363 // Now possibly store the information for subsequent accesses to the shape
6365 if( aInfo.nShapeId )
6367 // Possibly allow replacement of textboxes with frames
6368 if( bCanBeReplaced
6369 && aInfo.nTxBxComp
6370 && (
6371 ( eShapeType == mso_sptTextSimple )
6372 || ( eShapeType == mso_sptTextBox )
6373 || ( eShapeType == mso_sptRectangle )
6374 || ( eShapeType == mso_sptRoundRectangle )
6377 aInfo.bReplaceByFly = true;
6379 m_xShapeInfosByTxBxComp->insert(std::make_shared<SvxMSDffShapeInfo>(
6380 aInfo));
6381 m_aShapeOrders.push_back(std::make_unique<SvxMSDffShapeOrder>(
6382 aInfo.nShapeId ));
6385 // and position the Stream correctly again
6386 rSt.Seek( nStartShapeCont + nLenShapeCont );
6387 return true;
6391 /*****************************************************************************
6393 Access to a shape at runtime (via the Shape-Id)
6394 ----------------------------
6395 ******************************************************************************/
6396 bool SvxMSDffManager::GetShape(sal_uLong nId, rtl::Reference<SdrObject>& rpShape,
6397 SvxMSDffImportData& rData)
6399 auto const pTmpRec = std::make_shared<SvxMSDffShapeInfo>(0, nId);
6401 SvxMSDffShapeInfos_ById::const_iterator const it =
6402 m_xShapeInfosById->find(pTmpRec);
6403 if (it == m_xShapeInfosById->end())
6404 return false;
6406 // Possibly delete old error flag.
6407 if( rStCtrl.GetError() )
6408 rStCtrl.ResetError();
6409 // store FilePos of the stream(s)
6410 sal_uInt64 nOldPosCtrl = rStCtrl.Tell();
6411 sal_uInt64 nOldPosData = pStData ? pStData->Tell() : nOldPosCtrl;
6412 // jump to the shape in the control stream
6413 sal_uInt64 const nFilePos((*it)->nFilePos);
6414 bool bSeeked = (nFilePos == rStCtrl.Seek(nFilePos));
6416 // if it failed, reset error statusF
6417 if (!bSeeked || rStCtrl.GetError())
6418 rStCtrl.ResetError();
6419 else
6420 rpShape = ImportObj( rStCtrl, rData, rData.aParentRect, rData.aParentRect, /*nCalledByGroup*/0, /*pShapeId*/nullptr );
6422 // restore old FilePos of the stream(s)
6423 rStCtrl.Seek( nOldPosCtrl );
6424 if( &rStCtrl != pStData && pStData )
6425 pStData->Seek( nOldPosData );
6426 return bool( rpShape );
6430 /** Access to a BLIP at runtime (if the Blip-Number is already known)
6432 bool SvxMSDffManager::GetBLIP( sal_uLong nIdx_, Graphic& rGraphic, tools::Rectangle* pVisArea )
6434 if (!pStData)
6435 return false;
6437 bool bOk = false; // initialize result variable
6439 // check if a graphic for this blipId is already imported
6440 if (nIdx_)
6442 auto iter = aEscherBlipCache.find(nIdx_);
6444 if (iter != aEscherBlipCache.end())
6446 /* if this entry is available */
6447 rGraphic = iter->second;
6448 if (rGraphic.GetType() != GraphicType::NONE)
6449 bOk = true;
6450 else
6451 aEscherBlipCache.erase(iter);
6455 if (!bOk)
6457 sal_uInt16 nIdx = sal_uInt16( nIdx_ );
6458 if (!nIdx || (m_pBLIPInfos->size() < nIdx))
6459 return false;
6461 // possibly delete old error flag(s)
6462 if( rStCtrl.GetError() )
6463 rStCtrl.ResetError();
6464 if( ( &rStCtrl != pStData )
6465 && pStData->GetError() )
6466 pStData->ResetError();
6468 // remember FilePos of the stream(s)
6469 sal_uInt64 nOldPosCtrl = rStCtrl.Tell();
6470 sal_uInt64 nOldPosData = pStData->Tell();
6472 // fetch matching info struct out of the pointer array
6473 SvxMSDffBLIPInfo& rInfo = (*m_pBLIPInfos)[ nIdx-1 ];
6474 // jump to the BLIP atom in the data stream
6475 bOk = checkSeek(*pStData, rInfo.nFilePos);
6476 // possibly reset error status
6477 if (!bOk || pStData->GetError())
6478 pStData->ResetError();
6479 else
6480 bOk = GetBLIPDirect( *pStData, rGraphic, pVisArea );
6481 if( pStData2 && !bOk )
6483 // Error, but the is a second chance: There is a second
6484 // data stream in which the graphic could be stored!
6485 if( pStData2->GetError() )
6486 pStData2->ResetError();
6487 sal_uInt64 nOldPosData2 = pStData2->Tell();
6488 // jump to the BLIP atom in the second data stream
6489 bOk = checkSeek(*pStData2, rInfo.nFilePos);
6490 // reset error status if necessary
6491 if (!bOk || pStData2->GetError())
6492 pStData2->ResetError();
6493 else
6494 bOk = GetBLIPDirect( *pStData2, rGraphic, pVisArea );
6495 // restore of FilePos of the second data stream
6496 pStData2->Seek( nOldPosData2 );
6498 // restore old FilePos of the stream(s)
6499 rStCtrl.Seek( nOldPosCtrl );
6500 if( &rStCtrl != pStData )
6501 pStData->Seek( nOldPosData );
6503 if (bOk)
6505 // create new BlipCacheEntry for this graphic
6506 aEscherBlipCache.insert(std::make_pair(nIdx_, rGraphic));
6510 return bOk;
6513 /* access to a BLIP at runtime (with correctly positioned stream)
6514 ---------------------------------
6515 ******************************************************************************/
6516 bool SvxMSDffManager::GetBLIPDirect( SvStream& rBLIPStream, Graphic& rData, tools::Rectangle* pVisArea )
6518 sal_uInt64 nOldPos = rBLIPStream.Tell();
6520 ErrCode nRes = ERRCODE_GRFILTER_OPENERROR; // initialize error variable
6522 // check whether it's really a BLIP
6523 sal_uInt32 nLength;
6524 sal_uInt16 nInst, nFbt( 0 );
6525 sal_uInt8 nVer;
6526 if( ReadCommonRecordHeader( rBLIPStream, nVer, nInst, nFbt, nLength) && ( 0xF018 <= nFbt ) && ( 0xF117 >= nFbt ) )
6528 Size aMtfSize100;
6529 bool bMtfBLIP = false;
6530 bool bZCodecCompression = false;
6531 // now position it exactly at the beginning of the embedded graphic
6532 sal_uLong nSkip = (nInst & 0x0001) ? 32 : 16;
6533 const OfficeArtBlipRecInstance aRecInstanse = OfficeArtBlipRecInstance(nInst & 0xFFFE);
6534 switch (aRecInstanse)
6536 case OfficeArtBlipRecInstance::EMF:
6537 case OfficeArtBlipRecInstance::WMF:
6538 case OfficeArtBlipRecInstance::PICT:
6540 rBLIPStream.SeekRel(nSkip + 20);
6542 // read in size of metafile in English Metric Units (EMUs)
6543 sal_Int32 width(0), height(0);
6544 rBLIPStream.ReadInt32(width).ReadInt32(height);
6545 aMtfSize100.setWidth(width);
6546 aMtfSize100.setHeight(height);
6548 // 1 EMU = 1/360,000 of a centimeter
6549 // scale to 1/100mm
6550 aMtfSize100.setWidth(aMtfSize100.Width() / 360);
6551 aMtfSize100.setHeight(aMtfSize100.Height() / 360);
6553 if (pVisArea) // seem that we currently are skipping the visarea position
6554 *pVisArea = tools::Rectangle(Point(), aMtfSize100);
6556 // skip rest of header
6557 nSkip = 6;
6558 bMtfBLIP = bZCodecCompression = true;
6560 break;
6561 case OfficeArtBlipRecInstance::JPEG_RGB:
6562 case OfficeArtBlipRecInstance::JPEG_CMYK:
6563 case OfficeArtBlipRecInstance::PNG:
6564 case OfficeArtBlipRecInstance::DIB:
6565 case OfficeArtBlipRecInstance::TIFF:
6566 nSkip += 1; // Skip one byte tag
6567 break;
6569 rBLIPStream.SeekRel( nSkip );
6571 SvStream* pGrStream = &rBLIPStream;
6572 std::unique_ptr<SvMemoryStream> xOut;
6573 if( bZCodecCompression )
6575 xOut.reset(new SvMemoryStream( 0x8000, 0x4000 ));
6576 ZCodec aZCodec( 0x8000, 0x8000 );
6577 aZCodec.BeginCompression();
6578 aZCodec.Decompress( rBLIPStream, *xOut );
6579 aZCodec.EndCompression();
6580 xOut->Seek( STREAM_SEEK_TO_BEGIN );
6581 xOut->SetResizeOffset( 0 ); // sj: #i102257# setting ResizeOffset of 0 prevents from seeking
6582 // behind the stream end (allocating too much memory)
6583 pGrStream = xOut.get();
6586 #ifdef DEBUG_FILTER_MSDFFIMP
6587 // extract graphics from ole storage into "dbggfxNNN.*"
6588 static sal_Int32 nGrfCount;
6590 OUString aFileName = "dbggfx" + OUString::number(nGrfCount++);
6591 switch (aRecInstanse)
6593 case OfficeArtBlipRecInstance::WMF:
6594 aFileName += ".wmf";
6595 break;
6596 case OfficeArtBlipRecInstance::EMF:
6597 aFileName += ".emf";
6598 break;
6599 case OfficeArtBlipRecInstance::PICT:
6600 aFileName += ".pct";
6601 break;
6602 case OfficeArtBlipRecInstance::JPEG_RGB:
6603 case OfficeArtBlipRecInstance::JPEG_CMYK:
6604 aFileName += ".jpg";
6605 break;
6606 case OfficeArtBlipRecInstance::PNG:
6607 aFileName += ".png";
6608 break;
6609 case OfficeArtBlipRecInstance::DIB:
6610 aFileName += ".bmp";
6611 break;
6612 case OfficeArtBlipRecInstance::TIFF:
6613 aFileName += ".tif";
6614 break;
6618 OUString aURLStr;
6619 if( osl::FileBase::getFileURLFromSystemPath( Application::GetAppFileName(), aURLStr ) == osl::FileBase::E_None )
6621 INetURLObject aURL( aURLStr );
6623 aURL.removeSegment();
6624 aURL.removeFinalSlash();
6625 aURL.Append( aFileName );
6627 aURLStr = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
6629 SAL_INFO("filter.ms", "dumping " << aURLStr);
6631 std::unique_ptr<SvStream> pDbgOut(::utl::UcbStreamHelper::CreateStream(aURLStr, StreamMode::TRUNC | StreamMode::WRITE));
6633 if( pDbgOut )
6635 if ( bZCodecCompression )
6637 pDbgOut->WriteBytes(xOut->GetData(), xOut->TellEnd());
6638 xOut->Seek(STREAM_SEEK_TO_BEGIN);
6640 else
6642 sal_Int32 nDbgLen = nLength - nSkip;
6643 if ( nDbgLen )
6645 std::vector<char> aData(nDbgLen);
6646 pGrStream->ReadBytes(aData.data(), nDbgLen);
6647 pDbgOut->WriteBytes(aData.data(), nDbgLen);
6648 pGrStream->SeekRel(-nDbgLen);
6653 #endif
6654 if (aRecInstanse == OfficeArtBlipRecInstance::DIB)
6655 { // getting the DIBs immediately
6656 Bitmap aNew;
6657 if( ReadDIB(aNew, *pGrStream, false) )
6659 rData = Graphic(BitmapEx(aNew));
6660 nRes = ERRCODE_NONE;
6663 else
6664 { // and unleash our filter
6665 GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
6666 // ImportUnloadedGraphic() may simply read the entire rest of the stream,
6667 // which may be very large if the whole document is large. Limit the read
6668 // size to the size of this record.
6669 sal_uInt64 maxSize = pGrStream == &rBLIPStream ? nLength : 0;
6670 Graphic aGraphic;
6672 // Size available in metafile header.
6673 if (aMtfSize100.getWidth() && aMtfSize100.getHeight())
6674 aGraphic = rGF.ImportUnloadedGraphic(*pGrStream, maxSize, &aMtfSize100);
6675 else
6676 aGraphic = rGF.ImportUnloadedGraphic(*pGrStream, maxSize);
6678 if (!aGraphic.IsNone())
6680 rData = std::move(aGraphic);
6681 nRes = ERRCODE_NONE;
6683 else
6684 nRes = rGF.ImportGraphic( rData, u"", *pGrStream );
6686 // SJ: I40472, sometimes the aspect ratio (aMtfSize100) does not match and we get scaling problems,
6687 // then it is better to use the prefsize that is stored within the metafile. Bug #72846# for what the
6688 // scaling has been implemented does not happen anymore.
6690 // For pict graphics we will furthermore scale the metafile, because font scaling leads to error if the
6691 // dxarray is empty (this has been solved in wmf/emf but not for pict)
6692 if (bMtfBLIP && (ERRCODE_NONE == nRes) && (rData.GetType() == GraphicType::GdiMetafile)
6693 && (aRecInstanse == OfficeArtBlipRecInstance::PICT))
6695 if ( ( aMtfSize100.Width() >= 1000 ) && ( aMtfSize100.Height() >= 1000 ) )
6696 { // #75956#, scaling does not work properly, if the graphic is less than 1cm
6697 GDIMetaFile aMtf( rData.GetGDIMetaFile() );
6698 const Size aOldSize( aMtf.GetPrefSize() );
6700 if( aOldSize.Width() && ( aOldSize.Width() != aMtfSize100.Width() ) &&
6701 aOldSize.Height() && ( aOldSize.Height() != aMtfSize100.Height() ) )
6703 aMtf.Scale( static_cast<double>(aMtfSize100.Width()) / aOldSize.Width(),
6704 static_cast<double>(aMtfSize100.Height()) / aOldSize.Height() );
6705 aMtf.SetPrefSize( aMtfSize100 );
6706 aMtf.SetPrefMapMode(MapMode(MapUnit::Map100thMM));
6707 rData = aMtf;
6712 // reset error status if necessary
6713 if ( ERRCODE_IO_PENDING == pGrStream->GetError() )
6714 pGrStream->ResetError();
6716 rBLIPStream.Seek( nOldPos ); // restore old FilePos of the stream
6718 return ( ERRCODE_NONE == nRes ); // return result
6721 /* also static */
6722 bool SvxMSDffManager::ReadCommonRecordHeader(SvStream& rSt,
6723 sal_uInt8& rVer, sal_uInt16& rInst, sal_uInt16& rFbt, sal_uInt32& rLength)
6725 sal_uInt16 nTmp(0);
6726 rSt.ReadUInt16( nTmp ).ReadUInt16( rFbt ).ReadUInt32( rLength );
6727 rVer = sal::static_int_cast< sal_uInt8 >(nTmp & 15);
6728 rInst = nTmp >> 4;
6729 if (!rSt.good())
6730 return false;
6731 if (rLength > nMaxLegalDffRecordLength)
6732 return false;
6733 return true;
6736 void SvxMSDffManager::ProcessClientAnchor(SvStream& rStData, sal_uInt32 nDatLen,
6737 std::unique_ptr<char[]>& rpBuff, sal_uInt32& rBuffLen )
6739 if( nDatLen )
6741 rBuffLen = std::min(rStData.remainingSize(), static_cast<sal_uInt64>(nDatLen));
6742 rpBuff.reset( new char[rBuffLen] );
6743 rBuffLen = rStData.ReadBytes(rpBuff.get(), rBuffLen);
6747 void SvxMSDffManager::ProcessClientData(SvStream& rStData, sal_uInt32 nDatLen,
6748 std::unique_ptr<char[]>& rpBuff, sal_uInt32& rBuffLen )
6750 if( nDatLen )
6752 rBuffLen = std::min(rStData.remainingSize(), static_cast<sal_uInt64>(nDatLen));
6753 rpBuff.reset( new char[rBuffLen] );
6754 rBuffLen = rStData.ReadBytes(rpBuff.get(), rBuffLen);
6759 void SvxMSDffManager::ProcessClientAnchor2( SvStream& /* rSt */, DffRecordHeader& /* rHd */ , DffObjData& /* rObj */ )
6761 // will be overridden by SJ in Draw
6764 bool SvxMSDffManager::GetOLEStorageName( sal_uInt32, OUString&, rtl::Reference<SotStorage>&, uno::Reference < embed::XStorage >& ) const
6766 return false;
6769 bool SvxMSDffManager::ShapeHasText( sal_uLong /* nShapeId */, sal_uLong /* nFilePos */ ) const
6771 return true;
6774 // #i32596# - add new parameter <_nCalledByGroup>
6775 rtl::Reference<SdrObject> SvxMSDffManager::ImportOLE( sal_uInt32 nOLEId,
6776 const Graphic& rGrf,
6777 const tools::Rectangle& rBoundRect,
6778 const tools::Rectangle& rVisArea,
6779 const int /* _nCalledByGroup */ ) const
6781 rtl::Reference<SdrObject> pRet;
6782 OUString sStorageName;
6783 rtl::Reference<SotStorage> xSrcStg;
6784 ErrCode nError = ERRCODE_NONE;
6785 uno::Reference < embed::XStorage > xDstStg;
6786 if( GetOLEStorageName( nOLEId, sStorageName, xSrcStg, xDstStg ))
6787 pRet = CreateSdrOLEFromStorage(
6788 *GetModel(),
6789 sStorageName,
6790 xSrcStg,
6791 xDstStg,
6792 rGrf,
6793 rBoundRect,
6794 rVisArea,
6795 pStData,
6796 nError,
6797 nSvxMSDffOLEConvFlags,
6798 embed::Aspects::MSOLE_CONTENT,
6799 maBaseURL);
6800 return pRet;
6803 bool SvxMSDffManager::MakeContentStream( SotStorage * pStor, const GDIMetaFile & rMtf )
6805 rtl::Reference<SotStorageStream> xStm = pStor->OpenSotStream(SVEXT_PERSIST_STREAM);
6806 xStm->SetVersion( pStor->GetVersion() );
6807 xStm->SetBufferSize( 8192 );
6809 Impl_OlePres aEle;
6810 // Convert the size in 1/100 mm
6811 // If a not applicable MapUnit (device dependent) is used,
6812 // SV tries to guess a best match for the right value
6813 Size aSize = rMtf.GetPrefSize();
6814 const MapMode& aMMSrc = rMtf.GetPrefMapMode();
6815 MapMode aMMDst( MapUnit::Map100thMM );
6816 aSize = OutputDevice::LogicToLogic( aSize, aMMSrc, aMMDst );
6817 aEle.SetSize( aSize );
6818 aEle.SetAspect( ASPECT_CONTENT );
6819 aEle.SetAdviseFlags( 2 );
6820 aEle.SetMtf( rMtf );
6821 aEle.Write( *xStm );
6823 xStm->SetBufferSize( 0 );
6824 return xStm->GetError() == ERRCODE_NONE;
6827 namespace {
6829 struct ClsIDs {
6830 sal_uInt32 nId;
6831 const char* pSvrName;
6832 const char* pDspName;
6837 const ClsIDs aClsIDs[] = {
6839 { 0x000212F0, "MSWordArt", "Microsoft Word Art" },
6840 { 0x000212F0, "MSWordArt.2", "Microsoft Word Art 2.0" },
6842 // MS Apps
6843 { 0x00030000, "ExcelWorksheet", "Microsoft Excel Worksheet" },
6844 { 0x00030001, "ExcelChart", "Microsoft Excel Chart" },
6845 { 0x00030002, "ExcelMacrosheet", "Microsoft Excel Macro" },
6846 { 0x00030003, "WordDocument", "Microsoft Word Document" },
6847 { 0x00030004, "MSPowerPoint", "Microsoft PowerPoint" },
6848 { 0x00030005, "MSPowerPointSho", "Microsoft PowerPoint Slide Show"},
6849 { 0x00030006, "MSGraph", "Microsoft Graph" },
6850 { 0x00030007, "MSDraw", "Microsoft Draw" },
6851 { 0x00030008, "Note-It", "Microsoft Note-It" },
6852 { 0x00030009, "WordArt", "Microsoft Word Art" },
6853 { 0x0003000a, "PBrush", "Microsoft PaintBrush Picture" },
6854 { 0x0003000b, "Equation", "Microsoft Equation Editor" },
6855 { 0x0003000c, "Package", "Package" },
6856 { 0x0003000d, "SoundRec", "Sound" },
6857 { 0x0003000e, "MPlayer", "Media Player" },
6858 // MS Demos
6859 { 0x0003000f, "ServerDemo", "OLE 1.0 Server Demo" },
6860 { 0x00030010, "Srtest", "OLE 1.0 Test Demo" },
6861 { 0x00030011, "SrtInv", "OLE 1.0 Inv Demo" },
6862 { 0x00030012, "OleDemo", "OLE 1.0 Demo" },
6864 // Coromandel / Dorai Swamy / 718-793-7963
6865 { 0x00030013, "CoromandelIntegra", "Coromandel Integra" },
6866 { 0x00030014, "CoromandelObjServer","Coromandel Object Server" },
6868 // 3-d Visions Corp / Peter Hirsch / 310-325-1339
6869 { 0x00030015, "StanfordGraphics", "Stanford Graphics" },
6871 // Deltapoint / Nigel Hearne / 408-648-4000
6872 { 0x00030016, "DGraphCHART", "DeltaPoint Graph Chart" },
6873 { 0x00030017, "DGraphDATA", "DeltaPoint Graph Data" },
6875 // Corel / Richard V. Woodend / 613-728-8200 x1153
6876 { 0x00030018, "PhotoPaint", "Corel PhotoPaint" },
6877 { 0x00030019, "CShow", "Corel Show" },
6878 { 0x0003001a, "CorelChart", "Corel Chart" },
6879 { 0x0003001b, "CDraw", "Corel Draw" },
6881 // Inset Systems / Mark Skiba / 203-740-2400
6882 { 0x0003001c, "HJWIN1.0", "Inset Systems" },
6884 // Mark V Systems / Mark McGraw / 818-995-7671
6885 { 0x0003001d, "ObjMakerOLE", "MarkV Systems Object Maker" },
6887 // IdentiTech / Mike Gilger / 407-951-9503
6888 { 0x0003001e, "FYI", "IdentiTech FYI" },
6889 { 0x0003001f, "FYIView", "IdentiTech FYI Viewer" },
6891 // Inventa Corporation / Balaji Varadarajan / 408-987-0220
6892 { 0x00030020, "Stickynote", "Inventa Sticky Note" },
6894 // ShapeWare Corp. / Lori Pearce / 206-467-6723
6895 { 0x00030021, "ShapewareVISIO10", "Shapeware Visio 1.0" },
6896 { 0x00030022, "ImportServer", "Spaheware Import Server" },
6898 // test app SrTest
6899 { 0x00030023, "SrvrTest", "OLE 1.0 Server Test" },
6901 // test app ClTest. Doesn't really work as a server but is in reg db
6902 { 0x00030025, "Cltest", "OLE 1.0 Client Test" },
6904 // Microsoft ClipArt Gallery Sherry Larsen-Holmes
6905 { 0x00030026, "MS_ClipArt_Gallery", "Microsoft ClipArt Gallery" },
6906 // Microsoft Project Cory Reina
6907 { 0x00030027, "MSProject", "Microsoft Project" },
6909 // Microsoft Works Chart
6910 { 0x00030028, "MSWorksChart", "Microsoft Works Chart" },
6912 // Microsoft Works Spreadsheet
6913 { 0x00030029, "MSWorksSpreadsheet", "Microsoft Works Spreadsheet" },
6915 // AFX apps - Dean McCrory
6916 { 0x0003002A, "MinSvr", "AFX Mini Server" },
6917 { 0x0003002B, "HierarchyList", "AFX Hierarchy List" },
6918 { 0x0003002C, "BibRef", "AFX BibRef" },
6919 { 0x0003002D, "MinSvrMI", "AFX Mini Server MI" },
6920 { 0x0003002E, "TestServ", "AFX Test Server" },
6922 // Ami Pro
6923 { 0x0003002F, "AmiProDocument", "Ami Pro Document" },
6925 // WordPerfect Presentations For Windows
6926 { 0x00030030, "WPGraphics", "WordPerfect Presentation" },
6927 { 0x00030031, "WPCharts", "WordPerfect Chart" },
6929 // MicroGrafx Charisma
6930 { 0x00030032, "Charisma", "MicroGrafx Charisma" },
6931 { 0x00030033, "Charisma_30", "MicroGrafx Charisma 3.0" },
6932 { 0x00030034, "CharPres_30", "MicroGrafx Charisma 3.0 Pres" },
6933 // MicroGrafx Draw
6934 { 0x00030035, "Draw", "MicroGrafx Draw" },
6935 // MicroGrafx Designer
6936 { 0x00030036, "Designer_40", "MicroGrafx Designer 4.0" },
6938 // STAR DIVISION
6939 { 0x00043AD2, "FontWork", "Star FontWork" },
6941 { 0, "", "" } };
6944 bool SvxMSDffManager::ConvertToOle2( SvStream& rStm, sal_uInt32 nReadLen,
6945 const GDIMetaFile * pMtf, const rtl::Reference<SotStorage>& rDest )
6947 bool bMtfRead = false;
6948 rtl::Reference<SotStorageStream> xOle10Stm = rDest->OpenSotStream( u"\1Ole10Native"_ustr,
6949 StreamMode::WRITE| StreamMode::SHARE_DENYALL );
6950 if( xOle10Stm->GetError() )
6951 return false;
6953 OUString aSvrName;
6954 sal_uInt32 nDummy0;
6955 sal_uInt32 nDummy1;
6956 sal_uInt32 nBytesRead = 0;
6959 sal_uInt32 nType(0);
6960 sal_uInt32 nRecType(0);
6961 sal_uInt32 nStrLen(0);
6963 rStm.ReadUInt32( nType );
6964 rStm.ReadUInt32( nRecType );
6965 rStm.ReadUInt32( nStrLen );
6966 if( nStrLen )
6968 if( 0x10000L > nStrLen )
6970 std::unique_ptr<char[]> pBuf(new char[ nStrLen ]);
6971 rStm.ReadBytes(pBuf.get(), nStrLen);
6972 aSvrName = OUString( pBuf.get(), static_cast<sal_uInt16>(nStrLen)-1, osl_getThreadTextEncoding() );
6974 else
6975 break;
6977 rStm.ReadUInt32( nDummy0 );
6978 rStm.ReadUInt32( nDummy1 );
6979 sal_uInt32 nDataLen(0);
6980 rStm.ReadUInt32( nDataLen );
6982 nBytesRead += 6 * sizeof( sal_uInt32 ) + nStrLen + nDataLen;
6984 if (rStm.good() && nReadLen > nBytesRead && nDataLen)
6986 if( xOle10Stm.is() )
6988 std::unique_ptr<sal_uInt8[]> pData(new sal_uInt8[ nDataLen ]);
6989 rStm.ReadBytes(pData.get(), nDataLen);
6991 // write to ole10 stream
6992 xOle10Stm->WriteUInt32( nDataLen );
6993 xOle10Stm->WriteBytes(pData.get(), nDataLen);
6994 xOle10Stm.clear();
6996 // set the compobj stream
6997 const ClsIDs* pIds;
6998 for( pIds = aClsIDs; pIds->nId; pIds++ )
7000 if( aSvrName == OUString::createFromAscii(pIds->pSvrName) )
7001 break;
7004 if( pIds->nId )
7006 // found!
7007 SotClipboardFormatId nCbFmt = SotExchange::RegisterFormatName( aSvrName );
7008 rDest->SetClass( SvGlobalName( pIds->nId, 0, 0, 0xc0,0,0,0,0,0,0,0x46 ), nCbFmt,
7009 OUString::createFromAscii( pIds->pDspName ) );
7011 else
7013 SotClipboardFormatId nCbFmt = SotExchange::RegisterFormatName( aSvrName );
7014 rDest->SetClass( SvGlobalName(), nCbFmt, aSvrName );
7017 else if( nRecType == 5 && !pMtf )
7019 sal_uInt64 nPos = rStm.Tell();
7020 sal_uInt16 sz[4];
7021 rStm.ReadBytes( sz, 8 );
7022 Graphic aGraphic;
7023 if( ERRCODE_NONE == GraphicConverter::Import( rStm, aGraphic ) && aGraphic.GetType() != GraphicType::NONE )
7025 const GDIMetaFile& rMtf = aGraphic.GetGDIMetaFile();
7026 MakeContentStream( rDest.get(), rMtf );
7027 bMtfRead = true;
7029 // set behind the data
7030 rStm.Seek( nPos + nDataLen );
7032 else
7033 rStm.SeekRel( nDataLen );
7035 } while (rStm.good() && nReadLen >= nBytesRead);
7037 if( !bMtfRead && pMtf )
7039 MakeContentStream( rDest.get(), *pMtf );
7040 return true;
7043 return false;
7046 static const char* GetInternalServerName_Impl( const SvGlobalName& aGlobName )
7048 if ( aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_60 )
7049 || aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 ) )
7050 return "swriter";
7051 else if ( aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_60 )
7052 || aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 ) )
7053 return "scalc";
7054 else if ( aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_60 )
7055 || aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ) )
7056 return "simpress";
7057 else if ( aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_60 )
7058 || aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 ) )
7059 return "sdraw";
7060 else if ( aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_60 )
7061 || aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 ) )
7062 return "smath";
7063 else if ( aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_60 )
7064 || aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 ) )
7065 return "schart";
7066 return nullptr;
7069 OUString SvxMSDffManager::GetFilterNameFromClassID( const SvGlobalName& aGlobName )
7071 if ( aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_60 ) )
7072 return u"StarOffice XML (Writer)"_ustr;
7074 if ( aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 ) )
7075 return u"writer8"_ustr;
7077 if ( aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_60 ) )
7078 return u"StarOffice XML (Calc)"_ustr;
7080 if ( aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 ) )
7081 return u"calc8"_ustr;
7083 if ( aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_60 ) )
7084 return u"StarOffice XML (Impress)"_ustr;
7086 if ( aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ) )
7087 return u"impress8"_ustr;
7089 if ( aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_60 ) )
7090 return u"StarOffice XML (Draw)"_ustr;
7092 if ( aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 ) )
7093 return u"draw8"_ustr;
7095 if ( aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_60 ) )
7096 return u"StarOffice XML (Math)"_ustr;
7098 if ( aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 ) )
7099 return u"math8"_ustr;
7101 if ( aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_60 ) )
7102 return u"StarOffice XML (Chart)"_ustr;
7104 if ( aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 ) )
7105 return u"chart8"_ustr;
7107 return OUString();
7110 void SvxMSDffManager::ExtractOwnStream(SotStorage& rSrcStg, SvMemoryStream& rMemStream)
7112 rtl::Reference<SotStorageStream> xStr
7113 = rSrcStg.OpenSotStream(u"package_stream"_ustr, StreamMode::STD_READ);
7114 xStr->ReadStream(rMemStream);
7117 css::uno::Reference < css::embed::XEmbeddedObject > SvxMSDffManager::CheckForConvertToSOObj( sal_uInt32 nConvertFlags,
7118 SotStorage& rSrcStg, const uno::Reference < embed::XStorage >& rDestStorage,
7119 const Graphic& rGrf,
7120 const tools::Rectangle& rVisArea, OUString const& rBaseURL)
7122 uno::Reference < embed::XEmbeddedObject > xObj;
7123 SvGlobalName aStgNm = rSrcStg.GetClassName();
7124 const char* pName = GetInternalServerName_Impl( aStgNm );
7125 OUString sStarName;
7126 if ( pName )
7127 sStarName = OUString::createFromAscii( pName );
7128 else if ( nConvertFlags )
7130 static constexpr struct ObjImpType
7132 sal_uInt32 nFlag;
7133 OUString aFactoryNm;
7134 // GlobalNameId
7135 sal_uInt32 n1;
7136 sal_uInt16 n2, n3;
7137 sal_uInt8 b8, b9, b10, b11, b12, b13, b14, b15;
7138 } aArr[] {
7139 { OLE_MATHTYPE_2_STARMATH, u"smath"_ustr, MSO_EQUATION3_CLASSID },
7140 { OLE_MATHTYPE_2_STARMATH, u"smath"_ustr, MSO_EQUATION2_CLASSID },
7141 { OLE_WINWORD_2_STARWRITER, u"swriter"_ustr, MSO_WW8_CLASSID },
7142 // Excel table
7143 { OLE_EXCEL_2_STARCALC, u"scalc"_ustr, MSO_EXCEL5_CLASSID },
7144 { OLE_EXCEL_2_STARCALC, u"scalc"_ustr, MSO_EXCEL8_CLASSID },
7145 // 114465: additional Excel OLE chart classId to above.
7146 { OLE_EXCEL_2_STARCALC, u"scalc"_ustr, MSO_EXCEL8_CHART_CLASSID },
7147 // PowerPoint presentation
7148 { OLE_POWERPOINT_2_STARIMPRESS, u"simpress"_ustr, MSO_PPT8_CLASSID },
7149 // PowerPoint slide
7150 { OLE_POWERPOINT_2_STARIMPRESS, u"simpress"_ustr, MSO_PPT8_SLIDE_CLASSID }
7153 for( const ObjImpType & rArr : aArr )
7155 if( nConvertFlags & rArr.nFlag )
7157 SvGlobalName aTypeName( rArr.n1, rArr.n2, rArr.n3,
7158 rArr.b8, rArr.b9, rArr.b10, rArr.b11,
7159 rArr.b12, rArr.b13, rArr.b14, rArr.b15 );
7161 if ( aStgNm == aTypeName )
7163 sStarName = rArr.aFactoryNm;
7164 break;
7170 if ( sStarName.getLength() )
7172 //TODO/MBA: check if (and when) storage and stream will be destroyed!
7173 std::shared_ptr<const SfxFilter> pFilter;
7174 SvMemoryStream aMemStream;
7175 if ( pName )
7177 // TODO/LATER: perhaps we need to retrieve VisArea and Metafile from the storage also
7178 SvxMSDffManager::ExtractOwnStream(rSrcStg, aMemStream);
7180 else
7182 rtl::Reference<SotStorage> xStorage = new SotStorage(false, aMemStream);
7183 rSrcStg.CopyTo( xStorage.get() );
7184 xStorage->Commit();
7185 xStorage.clear();
7186 OUString aType = SfxFilter::GetTypeFromStorage( rSrcStg );
7187 if (aType.getLength() && !comphelper::IsFuzzing())
7189 SfxFilterMatcher aMatch( sStarName );
7190 pFilter = aMatch.GetFilter4EA( aType );
7194 #ifdef DEBUG_FILTER_MSFILTER
7195 // extract embedded ole streams into "/tmp/embedded_stream_NNN"
7196 static sal_Int32 nOleCount(0);
7197 OUString aTmpName("/tmp/embedded_stream_");
7198 aTmpName += OUString::number(nOleCount++);
7199 aTmpName += ".bin";
7200 SvFileStream aTmpStream(aTmpName,StreamMode::READ|StreamMode::WRITE|StreamMode::TRUNC);
7201 xMemStream->Seek(0);
7202 aTmpStream.WriteStream(*xMemStream);
7203 aTmpStream.Close();
7204 #endif
7205 if ( pName || pFilter )
7207 //Reuse current ole name
7208 OUString aDstStgName = MSO_OLE_Obj + OUString::number(nMSOleObjCntr);
7210 OUString aFilterName;
7211 if ( pFilter )
7212 aFilterName = pFilter->GetName();
7213 else
7214 aFilterName = SvxMSDffManager::GetFilterNameFromClassID( aStgNm );
7216 uno::Sequence<beans::PropertyValue> aMedium(aFilterName.isEmpty() ? 3 : 4);
7217 auto pMedium = aMedium.getArray();
7218 pMedium[0].Name = "InputStream";
7219 uno::Reference < io::XInputStream > xStream = new ::utl::OSeekableInputStreamWrapper( aMemStream );
7220 pMedium[0].Value <<= xStream;
7221 pMedium[1].Name = "URL";
7222 pMedium[1].Value <<= u"private:stream"_ustr;
7223 pMedium[2].Name = "DocumentBaseURL";
7224 pMedium[2].Value <<= rBaseURL;
7226 if ( !aFilterName.isEmpty() )
7228 pMedium[3].Name = "FilterName";
7229 pMedium[3].Value <<= aFilterName;
7232 OUString aName( aDstStgName );
7233 comphelper::EmbeddedObjectContainer aCnt( rDestStorage );
7234 xObj = aCnt.InsertEmbeddedObject(aMedium, aName, &rBaseURL);
7236 if ( !xObj.is() )
7238 if( !aFilterName.isEmpty() )
7240 // throw the filter parameter away as workaround
7241 aMedium.realloc( 2 );
7242 xObj = aCnt.InsertEmbeddedObject(aMedium, aName, &rBaseURL);
7245 if ( !xObj.is() )
7246 return xObj;
7249 // JP 26.10.2001: Bug 93374 / 91928 the writer
7250 // objects need the correct visarea needs the
7251 // correct visarea, but this is not true for
7252 // PowerPoint (see bugdoc 94908b)
7253 // SJ: 19.11.2001 bug 94908, also chart objects
7254 // needs the correct visarea
7256 // If pName is set this is an own embedded object, it should have the correct size internally
7257 // TODO/LATER: it might make sense in future to set the size stored in internal object
7258 if( !pName && ( sStarName == "swriter" || sStarName == "scalc" ) )
7260 // TODO/LATER: ViewAspect must be passed from outside!
7261 sal_Int64 nViewAspect = embed::Aspects::MSOLE_CONTENT;
7262 MapMode aMapMode( VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nViewAspect ) ) );
7263 Size aSz;
7264 if ( rVisArea.IsEmpty() )
7265 aSz = lcl_GetPrefSize(rGrf, aMapMode );
7266 else
7268 aSz = rVisArea.GetSize();
7269 aSz = OutputDevice::LogicToLogic( aSz, MapMode( MapUnit::Map100thMM ), aMapMode );
7272 // don't modify the object
7273 //TODO/LATER: remove those hacks, that needs to be done differently!
7274 //xIPObj->EnableSetModified( sal_False );
7275 awt::Size aSize;
7276 aSize.Width = aSz.Width();
7277 aSize.Height = aSz.Height();
7278 xObj->setVisualAreaSize( nViewAspect, aSize );
7279 //xIPObj->EnableSetModified( sal_True );
7281 else if ( sStarName == "smath" )
7282 { // SJ: force the object to recalc its visarea
7283 //TODO/LATER: wait for PrinterChangeNotification
7284 //xIPObj->OnDocumentPrinterChanged( NULL );
7289 return xObj;
7292 // TODO/MBA: code review and testing!
7293 rtl::Reference<SdrOle2Obj> SvxMSDffManager::CreateSdrOLEFromStorage(
7294 SdrModel& rSdrModel,
7295 const OUString& rStorageName,
7296 rtl::Reference<SotStorage> const & rSrcStorage,
7297 const uno::Reference < embed::XStorage >& xDestStorage,
7298 const Graphic& rGrf,
7299 const tools::Rectangle& rBoundRect,
7300 const tools::Rectangle& rVisArea,
7301 SvStream* pDataStrm,
7302 ErrCode& rError,
7303 sal_uInt32 nConvertFlags,
7304 sal_Int64 nRecommendedAspect,
7305 OUString const& rBaseURL)
7307 sal_Int64 nAspect = nRecommendedAspect;
7308 rtl::Reference<SdrOle2Obj> pRet;
7309 if( rSrcStorage.is() && xDestStorage.is() && rStorageName.getLength() )
7311 comphelper::EmbeddedObjectContainer aCnt( xDestStorage );
7312 // does the 01Ole-Stream exist at all?
7313 // (that's not the case for e.g. Fontwork )
7314 // If that's not the case -> include it as graphic
7315 bool bValidStorage = false;
7316 OUString aDstStgName = MSO_OLE_Obj + OUString::number( ++nMSOleObjCntr );
7319 rtl::Reference<SotStorage> xObjStg = rSrcStorage->OpenSotStorage(rStorageName);
7320 if( xObjStg.is() )
7323 sal_uInt8 aTestA[10]; // exist the \1CompObj-Stream ?
7324 rtl::Reference<SotStorageStream> xSrcTst = xObjStg->OpenSotStream(u"\1CompObj"_ustr);
7325 bValidStorage = xSrcTst.is() && sizeof( aTestA ) ==
7326 xSrcTst->ReadBytes(aTestA, sizeof(aTestA));
7327 if( !bValidStorage )
7329 // or the \1Ole-Stream ?
7330 xSrcTst = xObjStg->OpenSotStream( u"\1Ole"_ustr );
7331 bValidStorage = xSrcTst.is() && sizeof(aTestA) ==
7332 xSrcTst->ReadBytes(aTestA, sizeof(aTestA));
7336 if( bValidStorage )
7338 if ( nAspect != embed::Aspects::MSOLE_ICON )
7340 // check whether the object is iconified one
7341 // usually this information is already known, the only exception
7342 // is a kind of embedded objects in Word documents
7343 // TODO/LATER: should the caller be notified if the aspect changes in future?
7345 rtl::Reference<SotStorageStream> xObjInfoSrc = xObjStg->OpenSotStream(
7346 u"\3ObjInfo"_ustr, StreamMode::STD_READ );
7347 if ( xObjInfoSrc.is() && !xObjInfoSrc->GetError() )
7349 sal_uInt8 nByte = 0;
7350 xObjInfoSrc->ReadUChar( nByte );
7351 if ( ( nByte >> 4 ) & embed::Aspects::MSOLE_ICON )
7352 nAspect = embed::Aspects::MSOLE_ICON;
7356 uno::Reference < embed::XEmbeddedObject > xObj( CheckForConvertToSOObj(
7357 nConvertFlags, *xObjStg, xDestStorage, rGrf,
7358 rVisArea, rBaseURL));
7359 if ( xObj.is() )
7361 // remember file name to use in the title bar
7362 INetURLObject aURL(rBaseURL);
7363 xObj->setContainerName(aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset));
7365 svt::EmbeddedObjectRef aObj( xObj, nAspect );
7367 // TODO/LATER: need MediaType
7368 aObj.SetGraphic( rGrf, OUString() );
7370 // TODO/MBA: check setting of PersistName
7371 pRet = new SdrOle2Obj(
7372 rSdrModel,
7373 aObj,
7374 OUString(),
7375 rBoundRect);
7377 // we have the Object, don't create another
7378 bValidStorage = false;
7384 if( bValidStorage )
7386 // object is not an own object
7387 rtl::Reference<SotStorage> xObjStor = SotStorage::OpenOLEStorage( xDestStorage, aDstStgName, StreamMode::READWRITE );
7389 if ( xObjStor.is() )
7391 rtl::Reference<SotStorage> xSrcStor = rSrcStorage->OpenSotStorage( rStorageName, StreamMode::READ );
7392 xSrcStor->CopyTo( xObjStor.get() );
7394 if( !xObjStor->GetError() )
7395 xObjStor->Commit();
7397 if( xObjStor->GetError() )
7399 rError = xObjStor->GetError();
7400 bValidStorage = false;
7402 else if( !xObjStor.is() )
7403 bValidStorage = false;
7406 else if( pDataStrm )
7408 sal_uInt32 nLen(0), nDummy(0);
7409 pDataStrm->ReadUInt32( nLen ).ReadUInt32( nDummy );
7410 if( ERRCODE_NONE != pDataStrm->GetError() ||
7411 // Id in BugDoc - exist there other Ids?
7412 // The ConvertToOle2 - does not check for consistent
7413 0x30008 != nDummy )
7414 bValidStorage = false;
7415 else
7417 // or is it an OLE-1 Stream in the DataStream?
7418 rtl::Reference<SotStorage> xObjStor = SotStorage::OpenOLEStorage( xDestStorage, aDstStgName );
7419 //TODO/MBA: remove metafile conversion from ConvertToOle2
7420 //when is this code used?!
7421 GDIMetaFile aMtf;
7422 bValidStorage = ConvertToOle2( *pDataStrm, nLen, &aMtf, xObjStor );
7423 xObjStor->Commit();
7427 if( bValidStorage )
7429 uno::Reference < embed::XEmbeddedObject > xObj = aCnt.GetEmbeddedObject( aDstStgName );
7430 if( xObj.is() )
7432 // remember file name to use in the title bar
7433 INetURLObject aURL( rBaseURL );
7434 xObj->setContainerName( aURL.GetLastName( INetURLObject::DecodeMechanism::WithCharset ) );
7436 // the visual area must be retrieved from the metafile (object doesn't know it so far)
7438 if ( nAspect != embed::Aspects::MSOLE_ICON )
7440 // working with visual area can switch the object to running state
7443 awt::Size aAwtSz;
7444 // the provided visual area should be used, if there is any
7445 if ( rVisArea.IsEmpty() )
7447 MapUnit aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
7448 Size aSz(lcl_GetPrefSize(rGrf, MapMode(aMapUnit)));
7449 aAwtSz.Width = aSz.Width();
7450 aAwtSz.Height = aSz.Height();
7452 else
7454 aAwtSz.Width = rVisArea.GetWidth();
7455 aAwtSz.Height = rVisArea.GetHeight();
7457 //xInplaceObj->EnableSetModified( sal_False );
7458 xObj->setVisualAreaSize( nAspect, aAwtSz );
7459 //xInplaceObj->EnableSetModified( sal_True );
7461 catch( const uno::Exception& )
7463 OSL_FAIL( "Could not set visual area of the object!" );
7467 svt::EmbeddedObjectRef aObj( xObj, nAspect );
7469 // TODO/LATER: need MediaType
7470 aObj.SetGraphic( rGrf, OUString() );
7472 pRet = new SdrOle2Obj(
7473 rSdrModel,
7474 aObj,
7475 aDstStgName,
7476 rBoundRect);
7481 return pRet;
7484 bool SvxMSDffManager::SetPropValue( const uno::Any& rAny, const uno::Reference< css::beans::XPropertySet > & rXPropSet,
7485 const OUString& rPropName )
7487 bool bRetValue = false;
7490 uno::Reference< beans::XPropertySetInfo >
7491 aXPropSetInfo( rXPropSet->getPropertySetInfo() );
7492 if ( aXPropSetInfo.is() )
7493 bRetValue = aXPropSetInfo->hasPropertyByName( rPropName );
7495 catch( const uno::Exception& )
7497 bRetValue = false;
7499 if ( bRetValue )
7503 rXPropSet->setPropertyValue( rPropName, rAny );
7504 bRetValue = true;
7506 catch( const uno::Exception& )
7508 bRetValue = false;
7511 return bRetValue;
7514 SvxMSDffImportRec::SvxMSDffImportRec()
7515 : nClientAnchorLen( 0 ),
7516 nClientDataLen( 0 ),
7517 nXAlign( 0 ), // position n cm from left
7518 nYAlign( 0 ), // position n cm below
7519 nGroupShapeBooleanProperties(0), // 16 settings: LayoutInCell/AllowOverlap/BehindDocument...
7520 nFlags( ShapeFlag::NONE ),
7521 nDxTextLeft( 144 ),
7522 nDyTextTop( 72 ),
7523 nDxTextRight( 144 ),
7524 nDyTextBottom( 72 ),
7525 nDxWrapDistLeft( 0 ),
7526 nDyWrapDistTop( 0 ),
7527 nDxWrapDistRight( 0 ),
7528 nDyWrapDistBottom(0 ),
7529 nCropFromTop( 0 ),
7530 nCropFromBottom( 0 ),
7531 nCropFromLeft( 0 ),
7532 nCropFromRight( 0 ),
7533 nNextShapeId( 0 ),
7534 nShapeId( 0 ),
7535 eShapeType( mso_sptNil ),
7536 relativeHorizontalWidth( -1 ),
7537 isHorizontalRule( false )
7539 eLineStyle = mso_lineSimple; // GPF-Bug #66227#
7540 eLineDashing = mso_lineSolid;
7541 bDrawHell = false;
7542 bHidden = false;
7544 bReplaceByFly = false;
7545 bVFlip = false;
7546 bHFlip = false;
7547 bAutoWidth = false;
7550 SvxMSDffImportRec::SvxMSDffImportRec(const SvxMSDffImportRec& rCopy)
7551 : pObj( rCopy.pObj ),
7552 nXAlign( rCopy.nXAlign ),
7553 nXRelTo( rCopy.nXRelTo ),
7554 nYAlign( rCopy.nYAlign ),
7555 nYRelTo( rCopy.nYRelTo ),
7556 nGroupShapeBooleanProperties(rCopy.nGroupShapeBooleanProperties),
7557 nFlags( rCopy.nFlags ),
7558 nDxTextLeft( rCopy.nDxTextLeft ),
7559 nDyTextTop( rCopy.nDyTextTop ),
7560 nDxTextRight( rCopy.nDxTextRight ),
7561 nDyTextBottom( rCopy.nDyTextBottom ),
7562 nDxWrapDistLeft( rCopy.nDxWrapDistLeft ),
7563 nDyWrapDistTop( rCopy.nDyWrapDistTop ),
7564 nDxWrapDistRight( rCopy.nDxWrapDistRight ),
7565 nDyWrapDistBottom(rCopy.nDyWrapDistBottom ),
7566 nCropFromTop( rCopy.nCropFromTop ),
7567 nCropFromBottom( rCopy.nCropFromBottom ),
7568 nCropFromLeft( rCopy.nCropFromLeft ),
7569 nCropFromRight( rCopy.nCropFromRight ),
7570 aTextId( rCopy.aTextId ),
7571 nNextShapeId( rCopy.nNextShapeId ),
7572 nShapeId( rCopy.nShapeId ),
7573 eShapeType( rCopy.eShapeType ),
7574 relativeHorizontalWidth( rCopy.relativeHorizontalWidth ),
7575 isHorizontalRule( rCopy.isHorizontalRule )
7577 eLineStyle = rCopy.eLineStyle; // GPF-Bug #66227#
7578 eLineDashing = rCopy.eLineDashing;
7579 bDrawHell = rCopy.bDrawHell;
7580 bHidden = rCopy.bHidden;
7581 bReplaceByFly = rCopy.bReplaceByFly;
7582 bAutoWidth = rCopy.bAutoWidth;
7583 bVFlip = rCopy.bVFlip;
7584 bHFlip = rCopy.bHFlip;
7585 nClientAnchorLen = rCopy.nClientAnchorLen;
7586 if( rCopy.nClientAnchorLen )
7588 pClientAnchorBuffer.reset( new char[ nClientAnchorLen ] );
7589 memcpy( pClientAnchorBuffer.get(),
7590 rCopy.pClientAnchorBuffer.get(),
7591 nClientAnchorLen );
7593 else
7594 pClientAnchorBuffer = nullptr;
7596 nClientDataLen = rCopy.nClientDataLen;
7597 if( rCopy.nClientDataLen )
7599 pClientDataBuffer.reset( new char[ nClientDataLen ] );
7600 memcpy( pClientDataBuffer.get(),
7601 rCopy.pClientDataBuffer.get(),
7602 nClientDataLen );
7604 else
7605 pClientDataBuffer = nullptr;
7607 if (rCopy.pWrapPolygon)
7608 pWrapPolygon = rCopy.pWrapPolygon;
7611 SvxMSDffImportRec::~SvxMSDffImportRec()
7615 void SvxMSDffManager::insertShapeId( sal_Int32 nShapeId, SdrObject* pShape )
7617 maShapeIdContainer[nShapeId] = pShape;
7620 void SvxMSDffManager::removeShapeId( SdrObject const * pShape )
7622 SvxMSDffShapeIdContainer::iterator aIter = std::find_if(maShapeIdContainer.begin(), maShapeIdContainer.end(),
7623 [&pShape](const SvxMSDffShapeIdContainer::value_type& rEntry) { return rEntry.second == pShape; });
7624 if (aIter != maShapeIdContainer.end())
7625 maShapeIdContainer.erase( aIter );
7628 SdrObject* SvxMSDffManager::getShapeForId( sal_Int32 nShapeId )
7630 SvxMSDffShapeIdContainer::iterator aIter( maShapeIdContainer.find(nShapeId) );
7631 return aIter != maShapeIdContainer.end() ? (*aIter).second : nullptr;
7634 SvxMSDffImportData::SvxMSDffImportData(const tools::Rectangle& rParentRect)
7635 : aParentRect(rParentRect)
7639 SvxMSDffImportData::~SvxMSDffImportData()
7643 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */