android: Update app-specific/MIME type icons
[LibreOffice.git] / filter / source / msfilter / msdffimp.cxx
blobc1cd089ce9747d44941f5aef4b0125be76972c29
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 <unotools/configmgr.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 OUStringLiteral MSO_OLE_Obj = u"MSO_OLE_Obj";
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 const OUStringLiteral sPath( u"Path" );
619 sal_Int16 nGluePointType = EnhancedCustomShapeGluePointType::SEGMENTS;
620 css::uno::Any* pAny = aGeometryItem.GetPropertyValueByName( sPath, "GluePointType" );
621 if ( pAny )
622 *pAny >>= nGluePointType;
623 else
625 OUString sShapeType;
626 pAny = aGeometryItem.GetPropertyValueByName( "Type" );
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, "Segments" );
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 :
702 nC--;
703 nPt += 3;
705 break;
707 case EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO :
708 case EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE :
710 nC--;
711 nPt += 3;
713 break;
714 case EnhancedCustomShapeSegmentCommand::ARCTO :
715 case EnhancedCustomShapeSegmentCommand::ARC :
716 case EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO :
717 case EnhancedCustomShapeSegmentCommand::CLOCKWISEARC :
719 nC--;
720 nPt += 4;
722 break;
728 pAny = aGeometryItem.GetPropertyValueByName( sPath, "Coordinates" );
729 if ( pAny )
731 css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aCoordinates;
732 *pAny >>= aCoordinates;
733 if ( nPt < o3tl::make_unsigned(aCoordinates.getLength()) )
735 nId = 4;
736 css::drawing::EnhancedCustomShapeParameterPair& rPara = aCoordinates.getArray()[ nPt ];
737 sal_Int32 nX = 0, nY = 0;
738 if ( ( rPara.First.Value >>= nX ) && ( rPara.Second.Value >>= nY ) )
740 static const OUStringLiteral sGluePoints( u"GluePoints" );
741 css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aGluePoints;
742 pAny = aGeometryItem.GetPropertyValueByName( sPath, sGluePoints );
743 if ( pAny )
744 *pAny >>= aGluePoints;
745 sal_Int32 nGluePoints = aGluePoints.getLength();
746 aGluePoints.realloc( nGluePoints + 1 );
747 auto pGluePoints = aGluePoints.getArray();
748 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pGluePoints[ nGluePoints ].First, nX );
749 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pGluePoints[ nGluePoints ].Second, nY );
750 PropertyValue aProp;
751 aProp.Name = sGluePoints;
752 aProp.Value <<= aGluePoints;
753 aGeometryItem.SetPropertyValue( sPath, aProp );
754 bValidGluePoint = true;
755 static_cast<SdrObjCustomShape*>(pO)->SetMergedItem( aGeometryItem );
756 SdrGluePointList* pLst = pO->ForceGluePointList();
757 if ( pLst->GetCount() > nGluePoints )
758 nId = static_cast<sal_Int32>((*pLst)[ static_cast<sal_uInt16>(nGluePoints) ].GetId() + 3 );
764 break;
765 default: ;
767 if ( bValidGluePoint )
769 Reference< XPropertySet > xPropSet( aXConnector, UNO_QUERY );
770 if ( xPropSet.is() )
772 if ( nN )
774 OUString aPropName( "EndShape" );
775 SetPropValue( Any(aXShape), xPropSet, aPropName );
776 aPropName = "EndGluePointIndex";
777 SetPropValue( Any(nId), xPropSet, aPropName );
779 else
781 OUString aPropName( "StartShape" );
782 SetPropValue( Any(aXShape), xPropSet, aPropName );
783 aPropName = "StartGluePointIndex";
784 SetPropValue( Any(nId), xPropSet, aPropName );
787 // Not sure what this is good for, repaint or broadcast of object change.
788 //( Thus I am adding repaint here
789 pO->SetChanged();
790 pO->BroadcastObjectChange();
800 static basegfx::B2DPolyPolygon GetLineArrow( const sal_Int32 nLineWidth, const sal_uInt32 eLineEnd,
801 const sal_uInt32 eLineWidth, const sal_uInt32 eLineLength,
802 sal_Int32& rnArrowWidth, bool& rbArrowCenter,
803 OUString& rsArrowName, bool bScaleArrow )
805 basegfx::B2DPolyPolygon aRetPolyPoly;
806 // 70 100mm = 2pt = 40 twip. In MS, line width less than 2pt has the same size arrow as 2pt
807 //If the unit is twip. Make all use this unit especially the critical value 70/40.
808 sal_Int32 nLineWidthCritical = bScaleArrow ? 40 : 70;
809 double fLineWidth = nLineWidth < nLineWidthCritical ? nLineWidthCritical : nLineWidth;
811 double fLengthMul, fWidthMul;
812 sal_Int32 nLineNumber;
813 switch( eLineLength )
815 default :
816 case mso_lineMediumLenArrow : fLengthMul = 3.0; nLineNumber = 2; break;
817 case mso_lineShortArrow : fLengthMul = 2.0; nLineNumber = 1; break;
818 case mso_lineLongArrow : fLengthMul = 5.0; nLineNumber = 3; break;
820 switch( eLineWidth )
822 default :
823 case mso_lineMediumWidthArrow : fWidthMul = 3.0; nLineNumber += 3; break;
824 case mso_lineNarrowArrow : fWidthMul = 2.0; break;
825 case mso_lineWideArrow : fWidthMul = 5.0; nLineNumber += 6; break;
828 rbArrowCenter = false;
829 OUStringBuffer aArrowName;
830 switch ( eLineEnd )
832 case mso_lineArrowEnd :
834 basegfx::B2DPolygon aTriangle;
835 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50, 0.0 ));
836 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth, fLengthMul * fLineWidth ));
837 aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth ));
838 aTriangle.setClosed(true);
839 aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle);
840 aArrowName.append("msArrowEnd ");
842 break;
844 case mso_lineArrowOpenEnd :
846 switch( eLineLength )
848 default :
849 case mso_lineMediumLenArrow : fLengthMul = 4.5; break;
850 case mso_lineShortArrow : fLengthMul = 3.5; break;
851 case mso_lineLongArrow : fLengthMul = 6.0; break;
853 switch( eLineWidth )
855 default :
856 case mso_lineMediumWidthArrow : fWidthMul = 4.5; break;
857 case mso_lineNarrowArrow : fWidthMul = 3.5; break;
858 case mso_lineWideArrow : fWidthMul = 6.0; break;
860 basegfx::B2DPolygon aTriangle;
861 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , 0.0 ));
862 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth, fLengthMul * fLineWidth * 0.91 ));
863 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.85, fLengthMul * fLineWidth ));
864 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50, fLengthMul * fLineWidth * 0.36 ));
865 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.15, fLengthMul * fLineWidth ));
866 aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth * 0.91 ));
867 aTriangle.setClosed(true);
868 aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle);
869 aArrowName.append("msArrowOpenEnd ");
871 break;
872 case mso_lineArrowStealthEnd :
874 basegfx::B2DPolygon aTriangle;
875 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , 0.0 ));
876 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth , fLengthMul * fLineWidth ));
877 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , fLengthMul * fLineWidth * 0.60 ));
878 aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth ));
879 aTriangle.setClosed(true);
880 aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle);
881 aArrowName.append("msArrowStealthEnd ");
883 break;
884 case mso_lineArrowDiamondEnd :
886 basegfx::B2DPolygon aTriangle;
887 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , 0.0 ));
888 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth , fLengthMul * fLineWidth * 0.50 ));
889 aTriangle.append(basegfx::B2DPoint( fWidthMul * fLineWidth * 0.50 , fLengthMul * fLineWidth ));
890 aTriangle.append(basegfx::B2DPoint( 0.0, fLengthMul * fLineWidth * 0.50 ));
891 aTriangle.setClosed(true);
892 aRetPolyPoly = basegfx::B2DPolyPolygon(aTriangle);
893 rbArrowCenter = true;
894 aArrowName.append("msArrowDiamondEnd ");
896 break;
897 case mso_lineArrowOvalEnd :
899 aRetPolyPoly = basegfx::B2DPolyPolygon(
900 XPolygon(
901 Point( static_cast<sal_Int32>( fWidthMul * fLineWidth * 0.50 ), 0 ),
902 static_cast<sal_Int32>( fWidthMul * fLineWidth * 0.50 ),
903 static_cast<sal_Int32>( fLengthMul * fLineWidth * 0.50 ),
904 0_deg100, 36000_deg100 ).getB2DPolygon() );
905 rbArrowCenter = true;
906 aArrowName.append("msArrowOvalEnd ");
908 break;
909 default: break;
911 aArrowName.append(nLineNumber);
912 rsArrowName = aArrowName.makeStringAndClear();
913 rnArrowWidth = static_cast<sal_Int32>( fLineWidth * fWidthMul );
915 return aRetPolyPoly;
918 void DffPropertyReader::ApplyLineAttributes( SfxItemSet& rSet, const MSO_SPT eShapeType ) const // #i28269#
920 sal_uInt32 nLineFlags(GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 ));
922 if(!IsHardAttribute( DFF_Prop_fLine ) && !IsCustomShapeStrokedByDefault( eShapeType ))
924 nLineFlags &= ~0x08;
927 if ( nLineFlags & 8 )
929 // Line Attributes
930 sal_Int32 nLineWidth = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_lineWidth, 9525 ));
932 // support LineCap
933 auto eLineCap = GetPropertyValue(DFF_Prop_lineEndCapStyle, mso_lineEndCapFlat);
935 switch(eLineCap)
937 default: /* case mso_lineEndCapFlat */
939 // no need to set, it is the default. If this changes, this needs to be activated
940 // rSet.Put(XLineCapItem(css::drawing::LineCap_BUTT));
941 break;
943 case mso_lineEndCapRound:
945 rSet.Put(XLineCapItem(css::drawing::LineCap_ROUND));
946 break;
948 case mso_lineEndCapSquare:
950 rSet.Put(XLineCapItem(css::drawing::LineCap_SQUARE));
951 break;
955 auto eLineDashing = GetPropertyValue( DFF_Prop_lineDashing, mso_lineSolid);
956 if (eLineDashing == mso_lineSolid || nLineWidth < 0)
957 rSet.Put(XLineStyleItem( drawing::LineStyle_SOLID ) );
958 else
960 // Despite of naming "dot" and "dash", that are all dashes and a "dot" can be longer
961 // than a "dash". The naming indicates the order, "dot" is always the first dash and
962 // "dash" is always the second dash. MS Office always starts with the longer dash, so
963 // set it here accordingly.
964 // The preset from binary is essentially the same as from OOXML. So here the same
965 // setting is used as in oox import. The comment corresponds to
966 // "dots, dotLen, dashes, dashLen, distance" there.
967 // MS Office uses always relative length, so no need to consider nLineWidth
968 // here. Values are of kind 300 for 300% in css::drawing::DashStyle, for example.
970 sal_uInt16 nDots = 1; // in all cases, "solid" is treated above
971 // initialize, will be changed if necessary
972 sal_uInt32 nDotLen = 300;
973 sal_uInt16 nDashes = 0;
974 sal_uInt32 nDashLen = 0;
975 sal_uInt32 nDistance = 300;
976 switch ( eLineDashing )
978 default:
979 case mso_lineDotSys : // 1 1 0 0 1
981 nDotLen =100;
982 nDistance = 100;
984 break;
986 case mso_lineDashGEL : // 1 4 0 0 3
988 nDotLen = 400;
990 break;
992 case mso_lineDashDotGEL : // 1 4 1 1 3
994 nDotLen = 400;
995 nDashes = 1;
996 nDashLen = 100;
998 break;
1000 case mso_lineLongDashGEL : // 1 8 0 0 3
1002 nDotLen = 800;
1004 break;
1006 case mso_lineLongDashDotGEL : // 1 8 1 1 3
1008 nDotLen = 800;
1009 nDashes = 1;
1010 nDashLen = 100;
1012 break;
1014 case mso_lineLongDashDotDotGEL: // 1 8 2 1 3
1016 nDotLen = 800;
1017 nDashes = 2;
1018 nDashLen = 100;
1020 break;
1022 case mso_lineDotGEL: // 1 1 0 0 3
1024 nDotLen = 100;
1026 break;
1028 case mso_lineDashSys: // 1 3 0 0 1
1030 nDistance = 100;
1032 break;
1034 case mso_lineDashDotSys: // 1 3 1 1 1
1036 nDashes = 1;
1037 nDashLen = 100;
1038 nDistance = 100;
1040 break;
1042 case mso_lineDashDotDotSys: // 1 3 2 1 1
1044 nDashes = 2;
1045 nDashLen = 100;
1046 nDistance = 100;
1048 break;
1050 rSet.Put( XLineDashItem( OUString(), XDash( css::drawing::DashStyle_RECTRELATIVE, nDots, nDotLen, nDashes, nDashLen, nDistance ) ) );
1051 rSet.Put( XLineStyleItem( drawing::LineStyle_DASH ) );
1053 rSet.Put( XLineColorItem( OUString(), rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_lineColor, 0 ) ) ) );
1054 if ( IsProperty( DFF_Prop_lineOpacity ) )
1056 double nTrans = GetPropertyValue(DFF_Prop_lineOpacity, 0x10000);
1057 nTrans = (nTrans * 100) / 65536;
1058 rSet.Put(XLineTransparenceItem(
1059 sal_uInt16(100 - ::rtl::math::round(nTrans))));
1062 rManager.ScaleEmu( nLineWidth );
1063 rSet.Put( XLineWidthItem( nLineWidth ) );
1065 // SJ: LineJoint (setting each time a line is set, because our internal joint type has another default)
1066 MSO_LineJoin eLineJointDefault = mso_lineJoinMiter;
1067 if ( eShapeType == mso_sptMin )
1068 eLineJointDefault = mso_lineJoinRound;
1069 auto eLineJoint = GetPropertyValue(DFF_Prop_lineJoinStyle, eLineJointDefault);
1070 css::drawing::LineJoint eXLineJoint( css::drawing::LineJoint_MITER );
1071 if ( eLineJoint == mso_lineJoinBevel )
1072 eXLineJoint = css::drawing::LineJoint_BEVEL;
1073 else if ( eLineJoint == mso_lineJoinRound )
1074 eXLineJoint = css::drawing::LineJoint_ROUND;
1075 rSet.Put( XLineJointItem( eXLineJoint ) );
1077 if ( nLineFlags & 0x10 )
1079 bool bScaleArrows = rManager.pSdrModel->GetScaleUnit() == MapUnit::MapTwip;
1081 // LineStart
1083 if ( IsProperty( DFF_Prop_lineStartArrowhead ) )
1085 auto eLineEnd = GetPropertyValue(DFF_Prop_lineStartArrowhead, 0);
1086 auto eWidth = GetPropertyValue(DFF_Prop_lineStartArrowWidth, mso_lineMediumWidthArrow);
1087 auto eLength = GetPropertyValue(DFF_Prop_lineStartArrowLength, mso_lineMediumLenArrow);
1089 sal_Int32 nArrowWidth;
1090 bool bArrowCenter;
1091 OUString aArrowName;
1092 basegfx::B2DPolyPolygon aPolyPoly(GetLineArrow( nLineWidth, eLineEnd, eWidth, eLength, nArrowWidth, bArrowCenter, aArrowName, bScaleArrows ));
1094 rSet.Put( XLineStartWidthItem( nArrowWidth ) );
1095 rSet.Put( XLineStartItem( aArrowName, aPolyPoly) );
1096 rSet.Put( XLineStartCenterItem( bArrowCenter ) );
1099 // LineEnd
1101 if ( IsProperty( DFF_Prop_lineEndArrowhead ) )
1103 auto eLineEnd = GetPropertyValue(DFF_Prop_lineEndArrowhead, 0);
1104 auto eWidth = GetPropertyValue(DFF_Prop_lineEndArrowWidth, mso_lineMediumWidthArrow);
1105 auto eLength = GetPropertyValue(DFF_Prop_lineEndArrowLength, mso_lineMediumLenArrow);
1107 sal_Int32 nArrowWidth;
1108 bool bArrowCenter;
1109 OUString aArrowName;
1110 basegfx::B2DPolyPolygon aPolyPoly(GetLineArrow( nLineWidth, eLineEnd, eWidth, eLength, nArrowWidth, bArrowCenter, aArrowName, bScaleArrows ));
1112 rSet.Put( XLineEndWidthItem( nArrowWidth ) );
1113 rSet.Put( XLineEndItem( aArrowName, aPolyPoly ) );
1114 rSet.Put( XLineEndCenterItem( bArrowCenter ) );
1118 else
1119 rSet.Put( XLineStyleItem( drawing::LineStyle_NONE ) );
1122 namespace {
1124 struct ShadeColor
1126 Color aColor;
1127 double fDist;
1129 ShadeColor( const Color& rC, double fR ) : aColor( rC ), fDist( fR ) {};
1134 static void GetShadeColors( const SvxMSDffManager& rManager, const DffPropertyReader& rProperties, SvStream& rIn, std::vector< ShadeColor >& rShadeColors )
1136 sal_uInt64 nPos = rIn.Tell();
1137 if ( rProperties.IsProperty( DFF_Prop_fillShadeColors ) )
1139 sal_uInt16 i = 0, nNumElem = 0;
1140 bool bOk = false;
1141 if (rProperties.SeekToContent(DFF_Prop_fillShadeColors, rIn))
1143 sal_uInt16 nNumElemReserved = 0, nSize = 0;
1144 rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemReserved ).ReadUInt16( nSize );
1145 //sanity check that the stream is long enough to fulfill nNumElem * 2 sal_Int32s
1146 bOk = rIn.remainingSize() / (2*sizeof(sal_Int32)) >= nNumElem;
1148 if (bOk)
1150 for ( ; i < nNumElem; i++ )
1152 sal_Int32 nColor(0);
1153 sal_Int32 nDist(0);
1155 rIn.ReadInt32( nColor ).ReadInt32( nDist );
1156 rShadeColors.emplace_back( rManager.MSO_CLR_ToColor( nColor, DFF_Prop_fillColor ), 1.0 - ( nDist / 65536.0 ) );
1160 if ( rShadeColors.empty() )
1162 rShadeColors.emplace_back( rManager.MSO_CLR_ToColor( rProperties.GetPropertyValue( DFF_Prop_fillBackColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillBackColor ), 0 );
1163 rShadeColors.emplace_back( rManager.MSO_CLR_ToColor( rProperties.GetPropertyValue( DFF_Prop_fillColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillColor ), 1 );
1165 rIn.Seek( nPos );
1168 static void ApplyRectangularGradientAsBitmap( const SvxMSDffManager& rManager, SvStream& rIn, SfxItemSet& rSet, const std::vector< ShadeColor >& rShadeColors, const DffObjData& rObjData, Degree100 nFix16Angle )
1170 Size aBitmapSizePixel( static_cast< sal_Int32 >( ( rObjData.aBoundRect.GetWidth() / 2540.0 ) * 90.0 ), // we will create a bitmap with 90 dpi
1171 static_cast< sal_Int32 >( ( rObjData.aBoundRect.GetHeight() / 2540.0 ) * 90.0 ) );
1172 if (aBitmapSizePixel.IsEmpty() || aBitmapSizePixel.Width() > 1024 || aBitmapSizePixel.Height() > 1024)
1173 return;
1175 double fFocusX = rManager.GetPropertyValue( DFF_Prop_fillToRight, 0 ) / 65536.0;
1176 double fFocusY = rManager.GetPropertyValue( DFF_Prop_fillToBottom, 0 ) / 65536.0;
1178 vcl::bitmap::RawBitmap aBitmap(aBitmapSizePixel, 24);
1180 for ( tools::Long nY = 0; nY < aBitmapSizePixel.Height(); nY++ )
1182 for ( tools::Long nX = 0; nX < aBitmapSizePixel.Width(); nX++ )
1184 double fX = static_cast< double >( nX ) / aBitmapSizePixel.Width();
1185 double fY = static_cast< double >( nY ) / aBitmapSizePixel.Height();
1187 double fD, fDist;
1188 if ( fX < fFocusX )
1190 if ( fY < fFocusY )
1192 if ( fX > fY )
1194 fDist = fY;
1195 fD = fFocusY;
1197 else
1199 fDist = fX;
1200 fD = fFocusX;
1203 else
1205 if ( fX > ( 1 - fY ) )
1207 fDist = 1 - fY;
1208 fD = 1 - fFocusY;
1210 else
1212 fDist = fX;
1213 fD = fFocusX;
1217 else
1219 if ( fY < fFocusY )
1221 if ( ( 1 - fX ) > fY )
1223 fDist = fY;
1224 fD = fFocusY;
1226 else
1228 fDist = 1 - fX;
1229 fD = 1 - fFocusX;
1232 else
1234 if ( ( 1 - fX ) > ( 1 - fY ) )
1236 fDist = 1 - fY;
1237 fD = 1 - fFocusY;
1239 else
1241 fDist = 1 - fX;
1242 fD = 1 - fFocusX;
1246 if ( fD != 0.0 )
1247 fDist /= fD;
1249 double fA = 0.0;
1250 Color aColorA = rShadeColors.front().aColor;
1251 double fB = 1.0;
1252 Color aColorB( aColorA );
1253 for ( const auto& rShadeColor : rShadeColors )
1255 if ( fA <= rShadeColor.fDist && rShadeColor.fDist <= fDist )
1257 fA = rShadeColor.fDist;
1258 aColorA = rShadeColor.aColor;
1260 if ( fDist < rShadeColor.fDist && rShadeColor.fDist <= fB )
1262 fB = rShadeColor.fDist;
1263 aColorB = rShadeColor.aColor;
1266 double fRed = aColorA.GetRed(), fGreen = aColorA.GetGreen(), fBlue = aColorA.GetBlue();
1267 double fD1 = fB - fA;
1268 if ( fD1 != 0.0 )
1270 fRed += ( ( ( fDist - fA ) * ( aColorB.GetRed() - aColorA.GetRed() ) ) / fD1 ); // + aQuantErrCurrScan[ nX ].fRed;
1271 fGreen += ( ( ( fDist - fA ) * ( aColorB.GetGreen() - aColorA.GetGreen() ) ) / fD1 ); // + aQuantErrCurrScan[ nX ].fGreen;
1272 fBlue += ( ( ( fDist - fA ) * ( aColorB.GetBlue() - aColorA.GetBlue() ) ) / fD1 ); // + aQuantErrCurrScan[ nX ].fBlue;
1274 sal_Int16 nRed = static_cast< sal_Int16 >( fRed + 0.5 );
1275 sal_Int16 nGreen = static_cast< sal_Int16 >( fGreen + 0.5 );
1276 sal_Int16 nBlue = static_cast< sal_Int16 >( fBlue + 0.5 );
1277 if ( nRed < 0 )
1278 nRed = 0;
1279 if ( nRed > 255 )
1280 nRed = 255;
1281 if ( nGreen < 0 )
1282 nGreen = 0;
1283 if ( nGreen > 255 )
1284 nGreen = 255;
1285 if ( nBlue < 0 )
1286 nBlue = 0;
1287 if ( nBlue > 255 )
1288 nBlue = 255;
1290 aBitmap.SetPixel(nY, nX, Color(static_cast<sal_Int8>(nRed), static_cast<sal_Int8>(nGreen), static_cast<sal_Int8>(nBlue)));
1293 BitmapEx aBitmapEx = vcl::bitmap::CreateFromData( std::move(aBitmap) );
1295 if ( nFix16Angle )
1297 bool bRotateWithShape = true; // sal_True seems to be default
1298 sal_uInt64 nPos = rIn.Tell();
1299 if ( const_cast< SvxMSDffManager& >( rManager ).maShapeRecords.SeekToContent( rIn, DFF_msofbtUDefProp, SEEK_FROM_CURRENT_AND_RESTART ) )
1301 const_cast< SvxMSDffManager& >( rManager ).maShapeRecords.Current()->SeekToBegOfRecord( rIn );
1302 DffPropertyReader aSecPropSet( rManager );
1303 aSecPropSet.ReadPropSet( rIn, nullptr );
1304 sal_Int32 nSecFillProperties = aSecPropSet.GetPropertyValue( DFF_Prop_fNoFillHitTest, 0x200020 );
1305 bRotateWithShape = ( nSecFillProperties & 0x0020 );
1307 rIn.Seek( nPos );
1308 if ( bRotateWithShape )
1310 // convert from 100th to 10th degrees
1311 aBitmapEx.Rotate( to<Degree10>(nFix16Angle), rShadeColors[ 0 ].aColor );
1313 BmpMirrorFlags nMirrorFlags = BmpMirrorFlags::NONE;
1314 if ( rObjData.nSpFlags & ShapeFlag::FlipV )
1315 nMirrorFlags |= BmpMirrorFlags::Vertical;
1316 if ( rObjData.nSpFlags & ShapeFlag::FlipH )
1317 nMirrorFlags |= BmpMirrorFlags::Horizontal;
1318 if ( nMirrorFlags != BmpMirrorFlags::NONE )
1319 aBitmapEx.Mirror( nMirrorFlags );
1323 rSet.Put(XFillBmpTileItem(false));
1324 rSet.Put(XFillBitmapItem(OUString(), Graphic(aBitmapEx)));
1327 void DffPropertyReader::ApplyFillAttributes( SvStream& rIn, SfxItemSet& rSet, const DffObjData& rObjData ) const
1329 sal_uInt32 nFillFlags(GetPropertyValue( DFF_Prop_fNoFillHitTest, 0 ));
1331 std::vector< ShadeColor > aShadeColors;
1332 GetShadeColors( rManager, *this, rIn, aShadeColors );
1334 if(!IsHardAttribute( DFF_Prop_fFilled ) && !IsCustomShapeFilledByDefault( rObjData.eShapeType ))
1336 nFillFlags &= ~0x10;
1339 if ( nFillFlags & 0x10 )
1341 auto eMSO_FillType = GetPropertyValue(DFF_Prop_fillType, mso_fillSolid);
1342 bool bUseSlideBackground = false;
1343 drawing::FillStyle eXFill = drawing::FillStyle_NONE;
1344 switch( eMSO_FillType )
1346 case mso_fillSolid : // Fill with a solid color
1347 eXFill = drawing::FillStyle_SOLID;
1348 break;
1349 case mso_fillPattern : // Fill with a pattern (bitmap)
1350 case mso_fillTexture : // A texture (pattern with its own color map)
1351 case mso_fillPicture : // Center a picture in the shape
1352 eXFill = drawing::FillStyle_BITMAP;
1353 break;
1354 case mso_fillShadeCenter : // Shade from bounding rectangle to end point
1356 //If it is imported as a bitmap, it will not work well with transparency especially 100
1357 //But the gradient look well comparing with imported as gradient. And rotate with shape
1358 //also works better. So here just keep it.
1359 if ( rObjData.aBoundRect.IsEmpty() )// size of object needed to be able
1360 eXFill = drawing::FillStyle_GRADIENT; // to create a bitmap substitution
1361 else
1362 eXFill = drawing::FillStyle_BITMAP;
1364 break;
1365 case mso_fillShade : // Shade from start to end points
1366 case mso_fillShadeShape : // Shade from shape outline to end point
1367 case mso_fillShadeScale : // Similar to mso_fillShade, but the fillAngle
1368 case mso_fillShadeTitle : // special type - shade to title --- for PP
1369 eXFill = drawing::FillStyle_GRADIENT;
1370 break;
1371 case mso_fillBackground : // Use the background fill color/pattern
1372 eXFill = drawing::FillStyle_NONE;
1373 bUseSlideBackground = true;
1374 break;
1375 default: break;
1377 rSet.Put( XFillStyleItem( eXFill ) );
1379 double dTrans = 1.0;
1380 double dBackTrans = 1.0;
1381 if (IsProperty(DFF_Prop_fillOpacity))
1383 dTrans = GetPropertyValue(DFF_Prop_fillOpacity, 0) / 65536.0;
1384 if ( eXFill != drawing::FillStyle_GRADIENT )
1386 dTrans = dTrans * 100;
1387 rSet.Put(XFillTransparenceItem(
1388 sal_uInt16(100 - ::rtl::math::round(dTrans))));
1392 if ( IsProperty(DFF_Prop_fillBackOpacity) )
1393 dBackTrans = GetPropertyValue(DFF_Prop_fillBackOpacity, 0) / 65536.0;
1395 if ( ( eMSO_FillType == mso_fillShadeCenter ) && ( eXFill == drawing::FillStyle_BITMAP ) )
1397 ApplyRectangularGradientAsBitmap( rManager, rIn, rSet, aShadeColors, rObjData, mnFix16Angle );
1399 else if ( eXFill == drawing::FillStyle_GRADIENT )
1401 ImportGradientColor ( rSet, eMSO_FillType, dTrans , dBackTrans );
1403 else if ( eXFill == drawing::FillStyle_BITMAP )
1405 if( IsProperty( DFF_Prop_fillBlip ) )
1407 Graphic aGraf;
1408 // first try to get BLIP from cache
1409 bool bOK = const_cast<SvxMSDffManager&>(rManager).GetBLIP( GetPropertyValue( DFF_Prop_fillBlip, 0 ), aGraf );
1410 // then try directly from stream (i.e. Excel chart hatches/bitmaps)
1411 if ( !bOK )
1412 bOK = SeekToContent( DFF_Prop_fillBlip, rIn ) && SvxMSDffManager::GetBLIPDirect( rIn, aGraf );
1413 if ( bOK )
1415 if ( eMSO_FillType == mso_fillPattern )
1417 Bitmap aBmp( aGraf.GetBitmapEx().GetBitmap() );
1418 if (aBmp.GetSizePixel().Width() == 8 &&
1419 aBmp.GetSizePixel().Height() == 8 &&
1420 aBmp.getPixelFormat() == vcl::PixelFormat::N8_BPP)
1422 Color aCol1( COL_WHITE ), aCol2( COL_WHITE );
1424 if ( IsProperty( DFF_Prop_fillColor ) )
1425 aCol1 = rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillColor, 0 ), DFF_Prop_fillColor );
1427 if ( IsProperty( DFF_Prop_fillBackColor ) )
1428 aCol2 = rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillBackColor, 0 ), DFF_Prop_fillBackColor );
1430 // Create a bitmap for the pattern with expected colors
1431 vcl::bitmap::RawBitmap aResult(Size(8, 8), 24);
1433 Bitmap::ScopedReadAccess pRead(aBmp);
1435 for (tools::Long y = 0; y < aResult.Height(); ++y)
1437 Scanline pScanlineRead = pRead->GetScanline( y );
1438 for (tools::Long x = 0; x < aResult.Width(); ++x)
1440 Color aReadColor;
1441 if (pRead->HasPalette())
1442 aReadColor = pRead->GetPaletteColor(pRead->GetIndexFromData(pScanlineRead, x));
1443 else
1444 aReadColor = pRead->GetPixelFromData(pScanlineRead, x);
1446 if (aReadColor == Color(0))
1447 aResult.SetPixel(y, x, aCol2);
1448 else
1449 aResult.SetPixel(y, x, aCol1);
1453 aGraf = Graphic(vcl::bitmap::CreateFromData(std::move(aResult)));
1456 rSet.Put(XFillBitmapItem(OUString(), aGraf));
1458 else if ( eMSO_FillType == mso_fillTexture )
1460 rSet.Put(XFillBmpTileItem(true));
1461 rSet.Put(XFillBitmapItem(OUString(), aGraf));
1462 rSet.Put(XFillBmpSizeXItem(GetPropertyValue(DFF_Prop_fillWidth, 0) / 360));
1463 rSet.Put(XFillBmpSizeYItem(GetPropertyValue(DFF_Prop_fillHeight, 0) / 360));
1464 rSet.Put(XFillBmpSizeLogItem(true));
1466 else
1468 rSet.Put(XFillBitmapItem(OUString(), std::move(aGraf)));
1469 rSet.Put(XFillBmpTileItem(false));
1474 else if (eXFill == drawing::FillStyle_NONE && bUseSlideBackground)
1476 rSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
1477 XFillUseSlideBackgroundItem aFillBgItem(true);
1478 rSet.Put(aFillBgItem);
1481 else
1482 rSet.Put( XFillStyleItem( drawing::FillStyle_NONE ) );
1485 void DffPropertyReader::ApplyCustomShapeTextAttributes( SfxItemSet& rSet ) const
1487 bool bVerticalText = false;
1488 sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 25 * 3600 ) / 360; // 0.25 cm (emu)
1489 sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 25 * 3600 ) / 360; // 0.25 cm (emu)
1490 sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 13 * 3600 ) / 360; // 0.13 cm (emu)
1491 sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 13 * 3600 ) /360; // 0.13 cm (emu)
1493 SdrTextVertAdjust eTVA;
1494 SdrTextHorzAdjust eTHA;
1496 if ( IsProperty( DFF_Prop_txflTextFlow ) )
1498 auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF;
1499 switch( eTextFlow )
1501 case mso_txflTtoBA : /* #68110# */ // Top to Bottom @-font, oben -> unten
1502 case mso_txflTtoBN : // Top to Bottom non-@, oben -> unten
1503 case mso_txflVertN : // Vertical, non-@, oben -> unten
1504 bVerticalText = true; // nTextRotationAngle += 27000;
1505 break;
1506 default: break;
1509 sal_Int32 nFontDirection = GetPropertyValue( DFF_Prop_cdirFont, mso_cdir0 );
1510 if ( ( nFontDirection == 1 ) || ( nFontDirection == 3 ) )
1511 bVerticalText = !bVerticalText;
1513 if ( bVerticalText )
1515 eTHA = SDRTEXTHORZADJUST_CENTER;
1517 // read text anchor
1518 sal_uInt32 eTextAnchor = GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop );
1520 switch( eTextAnchor )
1522 case mso_anchorTop:
1523 case mso_anchorTopCentered:
1524 case mso_anchorTopBaseline:
1525 case mso_anchorTopCenteredBaseline:
1526 eTHA = SDRTEXTHORZADJUST_RIGHT;
1527 break;
1529 case mso_anchorMiddle :
1530 case mso_anchorMiddleCentered:
1531 eTHA = SDRTEXTHORZADJUST_CENTER;
1532 break;
1534 case mso_anchorBottom:
1535 case mso_anchorBottomCentered:
1536 case mso_anchorBottomBaseline:
1537 case mso_anchorBottomCenteredBaseline:
1538 eTHA = SDRTEXTHORZADJUST_LEFT;
1539 break;
1541 // if there is a 100% use of following attributes, the textbox can been aligned also in vertical direction
1542 switch ( eTextAnchor )
1544 case mso_anchorTopCentered :
1545 case mso_anchorMiddleCentered :
1546 case mso_anchorBottomCentered :
1547 case mso_anchorTopCenteredBaseline:
1548 case mso_anchorBottomCenteredBaseline:
1549 eTVA = SDRTEXTVERTADJUST_CENTER;
1550 break;
1552 default :
1553 eTVA = SDRTEXTVERTADJUST_TOP;
1554 break;
1557 else
1559 eTVA = SDRTEXTVERTADJUST_CENTER;
1561 // read text anchor
1562 sal_uInt32 eTextAnchor = GetPropertyValue( DFF_Prop_anchorText, mso_anchorTop );
1564 switch( eTextAnchor )
1566 case mso_anchorTop:
1567 case mso_anchorTopCentered:
1568 case mso_anchorTopBaseline:
1569 case mso_anchorTopCenteredBaseline:
1570 eTVA = SDRTEXTVERTADJUST_TOP;
1571 break;
1573 case mso_anchorMiddle :
1574 case mso_anchorMiddleCentered:
1575 eTVA = SDRTEXTVERTADJUST_CENTER;
1576 break;
1578 case mso_anchorBottom:
1579 case mso_anchorBottomCentered:
1580 case mso_anchorBottomBaseline:
1581 case mso_anchorBottomCenteredBaseline:
1582 eTVA = SDRTEXTVERTADJUST_BOTTOM;
1583 break;
1585 // if there is a 100% usage of following attributes, the textbox can be aligned also in horizontal direction
1586 switch ( eTextAnchor )
1588 case mso_anchorTopCentered :
1589 case mso_anchorMiddleCentered :
1590 case mso_anchorBottomCentered :
1591 case mso_anchorTopCenteredBaseline:
1592 case mso_anchorBottomCenteredBaseline:
1593 eTHA = SDRTEXTHORZADJUST_CENTER; // the text has to be displayed using the full width;
1594 break;
1596 default :
1597 eTHA = SDRTEXTHORZADJUST_LEFT;
1598 break;
1601 rSet.Put( SvxFrameDirectionItem( bVerticalText ? SvxFrameDirection::Vertical_RL_TB : SvxFrameDirection::Horizontal_LR_TB, EE_PARA_WRITINGDIR ) );
1603 rSet.Put( SdrTextVertAdjustItem( eTVA ) );
1604 rSet.Put( SdrTextHorzAdjustItem( eTHA ) );
1606 rSet.Put( makeSdrTextLeftDistItem( nTextLeft ) );
1607 rSet.Put( makeSdrTextRightDistItem( nTextRight ) );
1608 rSet.Put( makeSdrTextUpperDistItem( nTextTop ) );
1609 rSet.Put( makeSdrTextLowerDistItem( nTextBottom ) );
1611 rSet.Put( makeSdrTextWordWrapItem( GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare) != mso_wrapNone ) );
1612 rSet.Put( makeSdrTextAutoGrowHeightItem( ( GetPropertyValue( DFF_Prop_FitTextToShape, 0 ) & 2 ) != 0 ) );
1615 void DffPropertyReader::ApplyCustomShapeGeometryAttributes( SvStream& rIn, SfxItemSet& rSet, const DffObjData& rObjData ) const
1618 sal_uInt32 nAdjustmentsWhichNeedsToBeConverted = 0;
1621 // creating SdrCustomShapeGeometryItem
1623 typedef std::vector< beans::PropertyValue > PropVec;
1625 // aPropVec will be filled with all PropertyValues
1626 PropVec aPropVec;
1627 PropertyValue aProp;
1630 // "Type" property, including the predefined CustomShape type name
1632 aProp.Name = "Type";
1633 aProp.Value <<= EnhancedCustomShapeTypeNames::Get( rObjData.eShapeType );
1634 aPropVec.push_back( aProp );
1637 // "ViewBox"
1640 sal_Int32 nCoordWidth = 21600; // needed to replace handle type center with absolute value
1641 sal_Int32 nCoordHeight= 21600;
1642 if ( IsProperty( DFF_Prop_geoLeft ) || IsProperty( DFF_Prop_geoTop ) || IsProperty( DFF_Prop_geoRight ) || IsProperty( DFF_Prop_geoBottom ) )
1644 css::awt::Rectangle aViewBox;
1645 aViewBox.X = GetPropertyValue( DFF_Prop_geoLeft, 0 );
1646 aViewBox.Y = GetPropertyValue( DFF_Prop_geoTop, 0 );
1647 aViewBox.Width = nCoordWidth = o3tl::saturating_sub<sal_Int32>(GetPropertyValue(DFF_Prop_geoRight, 21600), aViewBox.X);
1648 aViewBox.Height = nCoordHeight = o3tl::saturating_sub<sal_Int32>(GetPropertyValue(DFF_Prop_geoBottom, 21600), aViewBox.Y);
1649 aProp.Name = "ViewBox";
1650 aProp.Value <<= aViewBox;
1651 aPropVec.push_back( aProp );
1654 // TextRotateAngle
1656 if ( IsProperty( DFF_Prop_txflTextFlow ) || IsProperty( DFF_Prop_cdirFont ) )
1658 sal_Int32 nTextRotateAngle = 0;
1659 auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF;
1661 if ( eTextFlow == mso_txflBtoT ) // Bottom to Top non-@
1662 nTextRotateAngle += 90;
1663 switch( GetPropertyValue( DFF_Prop_cdirFont, mso_cdir0 ) ) // SJ: mso_cdir90 and mso_cdir270 will be simulated by
1664 { // activating vertical writing for the text objects
1665 case mso_cdir90 :
1667 if ( eTextFlow == mso_txflTtoBA )
1668 nTextRotateAngle -= 180;
1670 break;
1671 case mso_cdir180: nTextRotateAngle -= 180; break;
1672 case mso_cdir270:
1674 if ( eTextFlow != mso_txflTtoBA )
1675 nTextRotateAngle -= 180;
1677 break;
1678 default: break;
1680 if ( nTextRotateAngle )
1682 double fTextRotateAngle = nTextRotateAngle;
1683 aProp.Name = "TextRotateAngle";
1684 aProp.Value <<= fTextRotateAngle;
1685 aPropVec.push_back( aProp );
1689 // "Extrusion" PropertySequence element
1691 bool bExtrusionOn = ( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 8 ) != 0;
1692 if ( bExtrusionOn )
1694 PropVec aExtrusionPropVec;
1696 // "Extrusion"
1697 aProp.Name = "Extrusion";
1698 aProp.Value <<= bExtrusionOn;
1699 aExtrusionPropVec.push_back( aProp );
1701 // "Brightness"
1702 // MS Office default 0x00004E20 16.16 FixedPoint, 20000/65536=0.30517, ODF default 33%.
1703 // Thus must set value even if default.
1704 double fBrightness = 20000.0;
1705 if ( IsProperty( DFF_Prop_c3DAmbientIntensity ) )
1707 // Value must be in range 0.0 to 1.0 in MS Office binary specification, but larger
1708 // values are in fact interpreted.
1709 fBrightness = GetPropertyValue( DFF_Prop_c3DAmbientIntensity, 0 );
1711 fBrightness /= 655.36;
1712 aProp.Name = "Brightness";
1713 aProp.Value <<= fBrightness;
1714 aExtrusionPropVec.push_back( aProp );
1716 // "Depth" in 1/100mm
1717 if ( IsProperty( DFF_Prop_c3DExtrudeBackward ) || IsProperty( DFF_Prop_c3DExtrudeForward ) )
1719 double fBackDepth = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DExtrudeBackward, 1270 * 360 ))) / 360.0;
1720 double fForeDepth = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DExtrudeForward, 0 ))) / 360.0;
1721 double fDepth = fBackDepth + fForeDepth;
1722 double fFraction = fDepth != 0.0 ? fForeDepth / fDepth : 0;
1723 EnhancedCustomShapeParameterPair aDepthParaPair;
1724 aDepthParaPair.First.Value <<= fDepth;
1725 aDepthParaPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
1726 aDepthParaPair.Second.Value <<= fFraction;
1727 aDepthParaPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
1728 aProp.Name = "Depth";
1729 aProp.Value <<= aDepthParaPair;
1730 aExtrusionPropVec.push_back( aProp );
1732 // "Diffusion"
1733 // ODF default is 0%, MS Office default is 100%. Thus must set value even if default.
1734 double fDiffusion = 100;
1735 if ( IsProperty( DFF_Prop_c3DDiffuseAmt ) )
1737 fDiffusion = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DDiffuseAmt, 0 ));
1738 fDiffusion /= 655.36;
1740 aProp.Name = "Diffusion";
1741 aProp.Value <<= fDiffusion;
1742 aExtrusionPropVec.push_back( aProp );
1744 // "NumberOfLineSegments"
1745 if ( IsProperty( DFF_Prop_c3DTolerance ) )
1747 aProp.Name = "NumberOfLineSegments";
1748 aProp.Value <<= static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DTolerance, 0 ));
1749 aExtrusionPropVec.push_back( aProp );
1751 // "LightFace"
1752 bool bExtrusionLightFace = ( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 1 ) != 0;
1753 aProp.Name = "LightFace";
1754 aProp.Value <<= bExtrusionLightFace;
1755 aExtrusionPropVec.push_back( aProp );
1756 // "FirstLightHarsh"
1757 bool bExtrusionFirstLightHarsh = ( GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 2 ) != 0;
1758 aProp.Name = "FirstLightHarsh";
1759 aProp.Value <<= bExtrusionFirstLightHarsh;
1760 aExtrusionPropVec.push_back( aProp );
1761 // "SecondLightHarsh"
1762 bool bExtrusionSecondLightHarsh = ( GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 1 ) != 0;
1763 aProp.Name = "SecondLightHarsh";
1764 aProp.Value <<= bExtrusionSecondLightHarsh;
1765 aExtrusionPropVec.push_back( aProp );
1767 // "FirstLightLevel"
1768 // MS Office default 0x00009470 16.16 FixedPoint, 38000/65536 = 0.5798, ODF default 66%.
1769 // Thus must set value even if default.
1770 double fFirstLightLevel = 38000.0;
1771 if ( IsProperty( DFF_Prop_c3DKeyIntensity ) )
1773 // value<0 and value>1 are allowed in MS Office. Clamp such in ODF export, not here.
1774 fFirstLightLevel = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DKeyIntensity, 0 ));
1776 fFirstLightLevel /= 655.36;
1777 aProp.Name = "FirstLightLevel";
1778 aProp.Value <<= fFirstLightLevel;
1779 aExtrusionPropVec.push_back( aProp );
1781 // "SecondLightLevel"
1782 // MS Office default 0x00009470 16.16 FixedPoint, 38000/65536 = 0.5798, ODF default 66%.
1783 // Thus must set value even if default.
1784 double fSecondLightLevel = 38000.0;
1785 if ( IsProperty( DFF_Prop_c3DFillIntensity ) )
1787 // value<0 and value>1 are allowed in MS Office. Clamp such in ODF export, not here.
1788 fSecondLightLevel = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DFillIntensity, 0 ));
1790 fSecondLightLevel /= 655.36;
1791 aProp.Name = "SecondLightLevel";
1792 aProp.Value <<= fSecondLightLevel;
1793 aExtrusionPropVec.push_back( aProp );
1795 // "FirstLightDirection"
1796 if ( IsProperty( DFF_Prop_c3DKeyX ) || IsProperty( DFF_Prop_c3DKeyY ) || IsProperty( DFF_Prop_c3DKeyZ ) )
1798 double fLightX = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DKeyX, 50000 )));
1799 double fLightY = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DKeyY, 0 )));
1800 double fLightZ = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DKeyZ, 10000 )));
1801 css::drawing::Direction3D aExtrusionFirstLightDirection( fLightX, fLightY, fLightZ );
1802 aProp.Name = "FirstLightDirection";
1803 aProp.Value <<= aExtrusionFirstLightDirection;
1804 aExtrusionPropVec.push_back( aProp );
1806 // "SecondLightDirection"
1807 if ( IsProperty( DFF_Prop_c3DFillX ) || IsProperty( DFF_Prop_c3DFillY ) || IsProperty( DFF_Prop_c3DFillZ ) )
1809 double fLight2X = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DFillX, sal_uInt32(-50000) )));
1810 double fLight2Y = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DFillY, 0 )));
1811 double fLight2Z = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DFillZ, 10000 )));
1812 css::drawing::Direction3D aExtrusionSecondLightDirection( fLight2X, fLight2Y, fLight2Z );
1813 aProp.Name = "SecondLightDirection";
1814 aProp.Value <<= aExtrusionSecondLightDirection;
1815 aExtrusionPropVec.push_back( aProp );
1818 // "Metal"
1819 bool bExtrusionMetal = ( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 4 ) != 0;
1820 aProp.Name = "Metal";
1821 aProp.Value <<= bExtrusionMetal;
1822 aExtrusionPropVec.push_back( aProp );
1823 aProp.Name = "MetalType";
1824 aProp.Value <<= css::drawing::EnhancedCustomShapeMetalType::MetalMSCompatible;
1825 aExtrusionPropVec.push_back(aProp);
1827 // "ShadeMode"
1828 if ( IsProperty( DFF_Prop_c3DRenderMode ) )
1830 sal_uInt32 nExtrusionRenderMode = GetPropertyValue( DFF_Prop_c3DRenderMode, 0 );
1831 css::drawing::ShadeMode eExtrusionShadeMode( css::drawing::ShadeMode_FLAT );
1832 if ( nExtrusionRenderMode == mso_Wireframe )
1833 eExtrusionShadeMode = css::drawing::ShadeMode_DRAFT;
1835 aProp.Name = "ShadeMode";
1836 aProp.Value <<= eExtrusionShadeMode;
1837 aExtrusionPropVec.push_back( aProp );
1839 // "RotateAngle" in Degree
1840 if ( IsProperty( DFF_Prop_c3DXRotationAngle ) || IsProperty( DFF_Prop_c3DYRotationAngle ) )
1842 double fAngleX = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DXRotationAngle, 0 ))) / 65536.0;
1843 double fAngleY = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DYRotationAngle, 0 ))) / 65536.0;
1844 EnhancedCustomShapeParameterPair aRotateAnglePair;
1845 aRotateAnglePair.First.Value <<= fAngleX;
1846 aRotateAnglePair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
1847 aRotateAnglePair.Second.Value <<= fAngleY;
1848 aRotateAnglePair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
1849 aProp.Name = "RotateAngle";
1850 aProp.Value <<= aRotateAnglePair;
1851 aExtrusionPropVec.push_back( aProp );
1854 // "AutoRotationCenter"
1855 if ( ( GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 8 ) == 0 )
1857 // "RotationCenter"
1858 if ( IsProperty( DFF_Prop_c3DRotationCenterX ) || IsProperty( DFF_Prop_c3DRotationCenterY ) || IsProperty( DFF_Prop_c3DRotationCenterZ ) )
1860 // tdf#145904 X- and Y-component is fraction, Z-component in EMU
1861 css::drawing::Direction3D aRotationCenter(
1862 static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DRotationCenterX, 0 ))) / 65536.0,
1863 static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DRotationCenterY, 0 ))) / 65536.0,
1864 static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DRotationCenterZ, 0 ))) / 360.0 );
1866 aProp.Name = "RotationCenter";
1867 aProp.Value <<= aRotationCenter;
1868 aExtrusionPropVec.push_back( aProp );
1871 // "Shininess"
1872 // MS Office default 5, ODF default 50%.
1873 if ( IsProperty( DFF_Prop_c3DShininess ) )
1875 double fShininess = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DShininess, 0 ));
1876 fShininess *= 10.0; // error in [MS ODRAW] (2021), type is not FixedPoint but long.
1877 aProp.Name = "Shininess";
1878 aProp.Value <<= fShininess;
1879 aExtrusionPropVec.push_back( aProp );
1882 // "Skew"
1883 // MS Office angle file value is 16.16 FixedPoint, default 0xFF790000,
1884 // -8847360/65536=-135, ODF default 45. Thus must set value even if default.
1885 double fSkewAngle = -135.0;
1886 // MS Office amount file value is signed integer in range 0xFFFFFF9C to 0x00000064,
1887 // default 0x00000032, ODF default 50.0
1888 double fSkewAmount = 50.0;
1889 if ( IsProperty( DFF_Prop_c3DSkewAmount ) || IsProperty( DFF_Prop_c3DSkewAngle ) )
1891 fSkewAmount = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DSkewAmount, 50 ));
1892 fSkewAngle = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DSkewAngle, sal::static_int_cast< sal_uInt32 >(-135 * 65536) ));
1893 fSkewAngle /= 65536.0;
1895 EnhancedCustomShapeParameterPair aSkewPair;
1896 aSkewPair.First.Value <<= fSkewAmount;
1897 aSkewPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
1898 aSkewPair.Second.Value <<= fSkewAngle;
1899 aSkewPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
1900 aProp.Name = "Skew";
1901 aProp.Value <<= aSkewPair;
1902 aExtrusionPropVec.push_back( aProp );
1904 // "Specularity"
1905 // Type Fixed point 16.16, percent in API
1906 if ( IsProperty( DFF_Prop_c3DSpecularAmt ) )
1908 double fSpecularity = static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DSpecularAmt, 0 ));
1909 fSpecularity /= 655.36;
1910 aProp.Name = "Specularity";
1911 aProp.Value <<= fSpecularity;
1912 aExtrusionPropVec.push_back( aProp );
1914 // "ProjectionMode"
1915 ProjectionMode eProjectionMode = (GetPropertyValue( DFF_Prop_fc3DFillHarsh, 0 ) & 4) ? ProjectionMode_PARALLEL : ProjectionMode_PERSPECTIVE;
1916 aProp.Name = "ProjectionMode";
1917 aProp.Value <<= eProjectionMode;
1918 aExtrusionPropVec.push_back( aProp );
1920 // "ViewPoint" in 1/100mm
1921 // MS Office default 1250000 EMU=3472.222 Hmm, ODF default 3.5cm
1922 // Thus must set value even if default.
1923 double fViewX = 1250000.0 / 360.0;
1924 double fViewY = -1250000.0 / 360.0;;
1925 double fViewZ = 9000000.0 / 360.0;
1926 if ( IsProperty( DFF_Prop_c3DXViewpoint ) || IsProperty( DFF_Prop_c3DYViewpoint ) || IsProperty( DFF_Prop_c3DZViewpoint ) )
1928 fViewX = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DXViewpoint, 1250000 ))) / 360.0;
1929 fViewY = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DYViewpoint, sal_uInt32(-1250000) )))/ 360.0;
1930 fViewZ = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DZViewpoint, 9000000 ))) / 360.0;
1932 css::drawing::Position3D aExtrusionViewPoint( fViewX, fViewY, fViewZ );
1933 aProp.Name = "ViewPoint";
1934 aProp.Value <<= aExtrusionViewPoint;
1935 aExtrusionPropVec.push_back( aProp );
1937 // "Origin"
1938 if ( IsProperty( DFF_Prop_c3DOriginX ) || IsProperty( DFF_Prop_c3DOriginY ) )
1940 double fOriginX = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DOriginX, 32768 )));
1941 double fOriginY = static_cast<double>(static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_c3DOriginY, sal_uInt32(-32768) )));
1942 fOriginX /= 65536;
1943 fOriginY /= 65536;
1944 EnhancedCustomShapeParameterPair aOriginPair;
1945 aOriginPair.First.Value <<= fOriginX;
1946 aOriginPair.First.Type = EnhancedCustomShapeParameterType::NORMAL;
1947 aOriginPair.Second.Value <<= fOriginY;
1948 aOriginPair.Second.Type = EnhancedCustomShapeParameterType::NORMAL;
1949 aProp.Name = "Origin";
1950 aProp.Value <<= aOriginPair;
1951 aExtrusionPropVec.push_back( aProp );
1953 // "ExtrusionColor"
1954 bool bExtrusionColor = IsProperty( DFF_Prop_c3DExtrusionColor ); // ( GetPropertyValue( DFF_Prop_fc3DLightFace ) & 2 ) != 0;
1955 aProp.Name = "Color";
1956 aProp.Value <<= bExtrusionColor;
1957 aExtrusionPropVec.push_back( aProp );
1958 if ( IsProperty( DFF_Prop_c3DExtrusionColor ) )
1959 rSet.Put( XSecondaryFillColorItem( OUString(), rManager.MSO_CLR_ToColor(
1960 GetPropertyValue( DFF_Prop_c3DExtrusionColor, 0 ), DFF_Prop_c3DExtrusionColor ) ) );
1961 // pushing the whole Extrusion element
1962 aProp.Name = "Extrusion";
1963 aProp.Value <<= comphelper::containerToSequence(aExtrusionPropVec);
1964 aPropVec.push_back( aProp );
1968 // "Equations" PropertySequence element
1970 if ( IsProperty( DFF_Prop_pFormulas ) )
1972 sal_uInt16 nNumElem = 0;
1974 if ( SeekToContent( DFF_Prop_pFormulas, rIn ) )
1976 sal_uInt16 nNumElemMem = 0;
1977 sal_uInt16 nElemSize = 8;
1978 rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemMem ).ReadUInt16( nElemSize );
1980 if ( nNumElem <= 128 )
1982 uno::Sequence< OUString > aEquations( nNumElem );
1983 for ( auto& rEquation : asNonConstRange(aEquations) )
1985 sal_Int16 nP1(0), nP2(0), nP3(0);
1986 sal_uInt16 nFlags(0);
1987 rIn.ReadUInt16( nFlags ).ReadInt16( nP1 ).ReadInt16( nP2 ).ReadInt16( nP3 );
1988 rEquation = EnhancedCustomShape2d::GetEquation( nFlags, nP1, nP2, nP3 );
1990 // pushing the whole Equations element
1991 aProp.Name = "Equations";
1992 aProp.Value <<= aEquations;
1993 aPropVec.push_back( aProp );
1998 // "Handles" PropertySequence element
2000 if ( IsProperty( DFF_Prop_Handles ) )
2002 sal_uInt16 nNumElem = 0;
2003 sal_uInt16 nElemSize = 36;
2005 if ( SeekToContent( DFF_Prop_Handles, rIn ) )
2007 sal_uInt16 nNumElemMem = 0;
2008 rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemMem ).ReadUInt16( nElemSize );
2010 bool bImport = false;
2011 if (nElemSize == 36)
2013 //sanity check that the stream is long enough to fulfill nNumElem * nElemSize;
2014 bImport = rIn.remainingSize() / nElemSize >= nNumElem;
2016 if (bImport)
2018 uno::Sequence< beans::PropertyValues > aHandles( nNumElem );
2019 auto aHandlesRange = asNonConstRange(aHandles);
2020 for (sal_uInt32 i = 0; i < nNumElem; ++i)
2022 PropVec aHandlePropVec;
2023 sal_uInt32 nFlagsTmp(0);
2024 sal_Int32 nPositionX(0), nPositionY(0), nCenterX(0), nCenterY(0), nRangeXMin(0), nRangeXMax(0), nRangeYMin(0), nRangeYMax(0);
2025 rIn.ReadUInt32( nFlagsTmp )
2026 .ReadInt32( nPositionX )
2027 .ReadInt32( nPositionY )
2028 .ReadInt32( nCenterX )
2029 .ReadInt32( nCenterY )
2030 .ReadInt32( nRangeXMin )
2031 .ReadInt32( nRangeXMax )
2032 .ReadInt32( nRangeYMin )
2033 .ReadInt32( nRangeYMax );
2034 SvxMSDffHandleFlags nFlags = static_cast<SvxMSDffHandleFlags>(nFlagsTmp);
2035 if ( nPositionX == 2 ) // replacing center position with absolute value
2036 nPositionX = nCoordWidth / 2;
2037 if ( nPositionY == 2 )
2038 nPositionY = nCoordHeight / 2;
2039 EnhancedCustomShapeParameterPair aPosition;
2040 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.First, nPositionX, true, true );
2041 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.Second, nPositionY, true, false );
2042 aProp.Name = "Position";
2043 aProp.Value <<= aPosition;
2044 aHandlePropVec.push_back( aProp );
2046 if ( nFlags & SvxMSDffHandleFlags::MIRRORED_X )
2048 aProp.Name = "MirroredX";
2049 aProp.Value <<= true;
2050 aHandlePropVec.push_back( aProp );
2052 if ( nFlags & SvxMSDffHandleFlags::MIRRORED_Y )
2054 aProp.Name = "MirroredY";
2055 aProp.Value <<= true;
2056 aHandlePropVec.push_back( aProp );
2058 if ( nFlags & SvxMSDffHandleFlags::SWITCHED )
2060 aProp.Name = "Switched";
2061 aProp.Value <<= true;
2062 aHandlePropVec.push_back( aProp );
2064 if ( nFlags & SvxMSDffHandleFlags::POLAR )
2066 if ( nCenterX == 2 )
2067 nCenterX = nCoordWidth / 2;
2068 if ( nCenterY == 2 )
2069 nCenterY = nCoordHeight / 2;
2070 if ((nPositionY >= 0x256 || nPositionY <= 0x107) && i < sizeof(sal_uInt32) * 8) // position y
2071 nAdjustmentsWhichNeedsToBeConverted |= ( 1U << i );
2072 EnhancedCustomShapeParameterPair aPolar;
2073 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPolar.First, nCenterX, bool( nFlags & SvxMSDffHandleFlags::CENTER_X_IS_SPECIAL ), true );
2074 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPolar.Second, nCenterY, bool( nFlags & SvxMSDffHandleFlags::CENTER_Y_IS_SPECIAL ), false );
2075 aProp.Name = "Polar";
2076 aProp.Value <<= aPolar;
2077 aHandlePropVec.push_back( aProp );
2079 if ( nFlags & SvxMSDffHandleFlags::MAP )
2081 if ( nCenterX == 2 )
2082 nCenterX = nCoordWidth / 2;
2083 if ( nCenterY == 2 )
2084 nCenterY = nCoordHeight / 2;
2085 EnhancedCustomShapeParameterPair aMap;
2086 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aMap.First, nCenterX, bool( nFlags & SvxMSDffHandleFlags::CENTER_X_IS_SPECIAL ), true );
2087 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aMap.Second, nCenterY, bool( nFlags & SvxMSDffHandleFlags::CENTER_Y_IS_SPECIAL ), false );
2088 aProp.Name = "Map";
2089 aProp.Value <<= aMap;
2090 aHandlePropVec.push_back( aProp );
2092 if ( nFlags & SvxMSDffHandleFlags::RANGE )
2094 if ( static_cast<sal_uInt32>(nRangeXMin) != 0x80000000 )
2096 if ( nRangeXMin == 2 )
2097 nRangeXMin = nCoordWidth / 2;
2098 EnhancedCustomShapeParameter aRangeXMinimum;
2099 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMinimum, nRangeXMin,
2100 bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL ), true );
2101 aProp.Name = "RangeXMinimum";
2102 aProp.Value <<= aRangeXMinimum;
2103 aHandlePropVec.push_back( aProp );
2105 if ( static_cast<sal_uInt32>(nRangeXMax) != 0x7fffffff )
2107 if ( nRangeXMax == 2 )
2108 nRangeXMax = nCoordWidth / 2;
2109 EnhancedCustomShapeParameter aRangeXMaximum;
2110 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMaximum, nRangeXMax,
2111 bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL ), false );
2112 aProp.Name = "RangeXMaximum";
2113 aProp.Value <<= aRangeXMaximum;
2114 aHandlePropVec.push_back( aProp );
2116 if ( static_cast<sal_uInt32>(nRangeYMin) != 0x80000000 )
2118 if ( nRangeYMin == 2 )
2119 nRangeYMin = nCoordHeight / 2;
2120 EnhancedCustomShapeParameter aRangeYMinimum;
2121 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMinimum, nRangeYMin,
2122 bool( nFlags & SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL ), true );
2123 aProp.Name = "RangeYMinimum";
2124 aProp.Value <<= aRangeYMinimum;
2125 aHandlePropVec.push_back( aProp );
2127 if ( static_cast<sal_uInt32>(nRangeYMax) != 0x7fffffff )
2129 if ( nRangeYMax == 2 )
2130 nRangeYMax = nCoordHeight / 2;
2131 EnhancedCustomShapeParameter aRangeYMaximum;
2132 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMaximum, nRangeYMax,
2133 bool( nFlags & SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL ), false );
2134 aProp.Name = "RangeYMaximum";
2135 aProp.Value <<= aRangeYMaximum;
2136 aHandlePropVec.push_back( aProp );
2139 if ( nFlags & SvxMSDffHandleFlags::RADIUS_RANGE )
2141 if ( static_cast<sal_uInt32>(nRangeXMin) != 0x7fffffff )
2143 if ( nRangeXMin == 2 )
2144 nRangeXMin = nCoordWidth / 2;
2145 EnhancedCustomShapeParameter aRadiusRangeMinimum;
2146 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMinimum, nRangeXMin,
2147 bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL ), true );
2148 aProp.Name = "RadiusRangeMinimum";
2149 aProp.Value <<= aRadiusRangeMinimum;
2150 aHandlePropVec.push_back( aProp );
2152 if ( static_cast<sal_uInt32>(nRangeXMax) != 0x80000000 )
2154 if ( nRangeXMax == 2 )
2155 nRangeXMax = nCoordWidth / 2;
2156 EnhancedCustomShapeParameter aRadiusRangeMaximum;
2157 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMaximum, nRangeXMax,
2158 bool( nFlags & SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL ), false );
2159 aProp.Name = "RadiusRangeMaximum";
2160 aProp.Value <<= aRadiusRangeMaximum;
2161 aHandlePropVec.push_back( aProp );
2164 if ( !aHandlePropVec.empty() )
2166 aHandlesRange[ i ] = comphelper::containerToSequence(aHandlePropVec);
2169 // pushing the whole Handles element
2170 aProp.Name = "Handles";
2171 aProp.Value <<= aHandles;
2172 aPropVec.push_back( aProp );
2175 else
2177 const mso_CustomShape* pDefCustomShape = GetCustomShapeContent( rObjData.eShapeType );
2178 if ( pDefCustomShape && pDefCustomShape->nHandles && pDefCustomShape->pHandles )
2180 sal_uInt32 i, nCnt = pDefCustomShape->nHandles;
2181 const SvxMSDffHandle* pData = pDefCustomShape->pHandles;
2182 for ( i = 0; i < nCnt; i++, pData++ )
2184 if ( pData->nFlags & SvxMSDffHandleFlags::POLAR )
2186 if ( ( pData->nPositionY >= 0x256 ) || ( pData->nPositionY <= 0x107 ) )
2187 nAdjustmentsWhichNeedsToBeConverted |= ( 1U << i );
2193 // "Path" PropertySequence element
2196 PropVec aPathPropVec;
2198 // "Path/ExtrusionAllowed"
2199 if ( IsHardAttribute( DFF_Prop_f3DOK ) )
2201 bool bExtrusionAllowed = ( GetPropertyValue( DFF_Prop_fFillOK, 0 ) & 16 ) != 0;
2202 aProp.Name = "ExtrusionAllowed";
2203 aProp.Value <<= bExtrusionAllowed;
2204 aPathPropVec.push_back( aProp );
2206 // "Path/ConcentricGradientFillAllowed"
2207 if ( IsHardAttribute( DFF_Prop_fFillShadeShapeOK ) )
2209 bool bConcentricGradientFillAllowed = ( GetPropertyValue( DFF_Prop_fFillOK, 0 ) & 2 ) != 0;
2210 aProp.Name = "ConcentricGradientFillAllowed";
2211 aProp.Value <<= bConcentricGradientFillAllowed;
2212 aPathPropVec.push_back( aProp );
2214 // "Path/TextPathAllowed"
2215 if ( IsHardAttribute( DFF_Prop_fGtextOK ) || ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x4000 ) )
2217 bool bTextPathAllowed = ( GetPropertyValue( DFF_Prop_fFillOK, 0 ) & 4 ) != 0;
2218 aProp.Name = "TextPathAllowed";
2219 aProp.Value <<= bTextPathAllowed;
2220 aPathPropVec.push_back( aProp );
2222 // Path/Coordinates
2223 if ( IsProperty( DFF_Prop_pVertices ) )
2225 css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aCoordinates;
2226 sal_uInt16 nNumElemVert = 0;
2227 sal_uInt16 nElemSizeVert = 8;
2229 if ( SeekToContent( DFF_Prop_pVertices, rIn ) )
2231 sal_uInt16 nNumElemMemVert = 0;
2232 rIn.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert );
2233 // If this value is 0xFFF0 then this record is an array of truncated 8 byte elements. Only the 4
2234 // low-order bytes are recorded
2235 if (nElemSizeVert == 0xFFF0)
2236 nElemSizeVert = 4;
2238 //sanity check that the stream is long enough to fulfill nNumElem * nElemSize;
2239 bool bImport = nElemSizeVert && (rIn.remainingSize() / nElemSizeVert >= nNumElemVert);
2240 if (bImport)
2242 aCoordinates.realloc( nNumElemVert );
2243 for (auto& rCoordinate : asNonConstRange(aCoordinates))
2245 sal_Int32 nX(0), nY(0);
2247 if ( nElemSizeVert == 8 )
2249 rIn.ReadInt32( nX )
2250 .ReadInt32( nY );
2252 else
2254 // The mso-spt19 (arc) uses this. But it needs unsigned integer. I don't
2255 // know if other shape types also need it. They can be added as necessary.
2256 bool bNeedsUnsigned = rObjData.eShapeType == mso_sptArc;
2257 if (bNeedsUnsigned)
2259 sal_uInt16 nTmpA(0), nTmpB(0);
2260 rIn.ReadUInt16(nTmpA)
2261 .ReadUInt16(nTmpB);
2262 nX = nTmpA;
2263 nY = nTmpB;
2265 else
2267 sal_Int16 nTmpA(0), nTmpB(0);
2268 rIn.ReadInt16( nTmpA )
2269 .ReadInt16( nTmpB );
2270 nX = nTmpA;
2271 nY = nTmpB;
2274 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rCoordinate.First, nX );
2275 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rCoordinate.Second, nY );
2278 aProp.Name = "Coordinates";
2279 aProp.Value <<= aCoordinates;
2280 aPathPropVec.push_back( aProp );
2282 // Path/Segments
2283 if ( IsProperty( DFF_Prop_pSegmentInfo ) )
2285 css::uno::Sequence< css::drawing::EnhancedCustomShapeSegment > aSegments;
2287 sal_uInt16 nNumElemSeg = 0;
2289 if ( SeekToContent( DFF_Prop_pSegmentInfo, rIn ) )
2291 sal_uInt16 nNumElemMemSeg = 0;
2292 sal_uInt16 nElemSizeSeg = 2;
2293 rIn.ReadUInt16( nNumElemSeg ).ReadUInt16( nNumElemMemSeg ).ReadUInt16( nElemSizeSeg );
2295 sal_uInt64 nMaxEntriesPossible = rIn.remainingSize() / sizeof(sal_uInt16);
2296 if (nNumElemSeg > nMaxEntriesPossible)
2298 SAL_WARN("filter.ms", "NumElem list is longer than remaining bytes, ppt or parser is wrong");
2299 nNumElemSeg = nMaxEntriesPossible;
2301 if ( nNumElemSeg )
2303 aSegments.realloc( nNumElemSeg );
2304 for (auto& rSegment : asNonConstRange(aSegments))
2306 sal_uInt16 nTmp(0);
2307 rIn.ReadUInt16( nTmp );
2308 sal_Int16 nCommand = EnhancedCustomShapeSegmentCommand::UNKNOWN;
2309 sal_Int16 nCnt = static_cast<sal_Int16>( nTmp & 0x1fff );//Last 13 bits for segment points number
2310 switch( nTmp >> 13 )//First 3 bits for command type
2312 case 0x0:
2313 nCommand = EnhancedCustomShapeSegmentCommand::LINETO;
2314 if ( !nCnt ) nCnt = 1;
2315 break;
2316 case 0x1:
2317 nCommand = EnhancedCustomShapeSegmentCommand::CURVETO;
2318 if ( !nCnt ) nCnt = 1;
2319 break;
2320 case 0x2:
2321 nCommand = EnhancedCustomShapeSegmentCommand::MOVETO;
2322 if ( !nCnt ) nCnt = 1;
2323 break;
2324 case 0x3:
2325 nCommand = EnhancedCustomShapeSegmentCommand::CLOSESUBPATH;
2326 nCnt = 0;
2327 break;
2328 case 0x4:
2329 nCommand = EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
2330 nCnt = 0;
2331 break;
2332 case 0x5:
2333 case 0x6:
2335 switch ( ( nTmp >> 8 ) & 0x1f )//5 bits next to command type is for path escape type
2337 case 0x0:
2339 //It is msopathEscapeExtension which is transformed into LINETO.
2340 //If issue happens, I think this part can be comment so that it will be taken as unknown command.
2341 //When export, origin data will be export without any change.
2342 nCommand = EnhancedCustomShapeSegmentCommand::LINETO;
2343 if ( !nCnt )
2344 nCnt = 1;
2346 break;
2347 case 0x1:
2349 nCommand = EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO;
2350 nCnt = ( nTmp & 0xff ) / 3;
2352 break;
2353 case 0x2:
2355 nCommand = EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE;
2356 nCnt = ( nTmp & 0xff ) / 3;
2358 break;
2359 case 0x3:
2361 nCommand = EnhancedCustomShapeSegmentCommand::ARCTO;
2362 nCnt = ( nTmp & 0xff ) >> 2;
2364 break;
2365 case 0x4:
2367 nCommand = EnhancedCustomShapeSegmentCommand::ARC;
2368 nCnt = ( nTmp & 0xff ) >> 2;
2370 break;
2371 case 0x5:
2373 nCommand = EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO;
2374 nCnt = ( nTmp & 0xff ) >> 2;
2376 break;
2377 case 0x6:
2379 nCommand = EnhancedCustomShapeSegmentCommand::CLOCKWISEARC;
2380 nCnt = ( nTmp & 0xff ) >> 2;
2382 break;
2383 case 0x7:
2385 nCommand = EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX;
2386 nCnt = nTmp & 0xff;
2388 break;
2389 case 0x8:
2391 nCommand = EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY;
2392 nCnt = nTmp & 0xff;
2394 break;
2395 case 0xa: nCommand = EnhancedCustomShapeSegmentCommand::NOFILL; nCnt = 0; break;
2396 case 0xb: nCommand = EnhancedCustomShapeSegmentCommand::NOSTROKE; nCnt = 0; break;
2399 break;
2401 // if the command is unknown, we will store all the data in nCnt, so it will be possible to export without loss
2402 if ( nCommand == EnhancedCustomShapeSegmentCommand::UNKNOWN )
2403 nCnt = static_cast<sal_Int16>(nTmp);
2404 rSegment.Command = nCommand;
2405 rSegment.Count = nCnt;
2408 aProp.Name = "Segments";
2409 aProp.Value <<= aSegments;
2410 aPathPropVec.push_back( aProp );
2412 // Path/StretchX
2413 if ( IsProperty( DFF_Prop_stretchPointX ) )
2415 sal_Int32 nStretchX = GetPropertyValue( DFF_Prop_stretchPointX, 0 );
2416 aProp.Name = "StretchX";
2417 aProp.Value <<= nStretchX;
2418 aPathPropVec.push_back( aProp );
2420 // Path/StretchX
2421 if ( IsProperty( DFF_Prop_stretchPointY ) )
2423 sal_Int32 nStretchY = GetPropertyValue( DFF_Prop_stretchPointY, 0 );
2424 aProp.Name = "StretchY";
2425 aProp.Value <<= nStretchY;
2426 aPathPropVec.push_back( aProp );
2428 // Path/TextFrames
2429 if ( IsProperty( DFF_Prop_textRectangles ) )
2431 sal_uInt16 nNumElem = 0;
2432 sal_uInt16 nElemSize = 16;
2434 if ( SeekToContent( DFF_Prop_textRectangles, rIn ) )
2436 sal_uInt16 nNumElemMem = 0;
2437 rIn.ReadUInt16( nNumElem ).ReadUInt16( nNumElemMem ).ReadUInt16( nElemSize );
2439 bool bImport = false;
2440 if (nElemSize == 16)
2442 //sanity check that the stream is long enough to fulfill nNumElem * nElemSize;
2443 bImport = rIn.remainingSize() / nElemSize >= nNumElem;
2445 if (bImport)
2447 css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aTextFrames( nNumElem );
2448 for (auto& rTextFrame : asNonConstRange(aTextFrames))
2450 sal_Int32 nLeft(0), nTop(0), nRight(0), nBottom(0);
2452 rIn.ReadInt32( nLeft )
2453 .ReadInt32( nTop )
2454 .ReadInt32( nRight )
2455 .ReadInt32( nBottom );
2457 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rTextFrame.TopLeft.First, nLeft );
2458 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rTextFrame.TopLeft.Second, nTop );
2459 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rTextFrame.BottomRight.First, nRight );
2460 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rTextFrame.BottomRight.Second, nBottom);
2462 aProp.Name = "TextFrames";
2463 aProp.Value <<= aTextFrames;
2464 aPathPropVec.push_back( aProp );
2467 //Path/GluePoints
2468 if ( IsProperty( DFF_Prop_connectorPoints ) )
2470 css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aGluePoints;
2471 sal_uInt16 nNumElemVert = 0;
2472 sal_uInt16 nElemSizeVert = 8;
2474 if ( SeekToContent( DFF_Prop_connectorPoints, rIn ) )
2476 sal_uInt16 nNumElemMemVert = 0;
2477 rIn.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert );
2478 // If this value is 0xFFF0 then this record is an array of truncated 8 byte elements. Only the 4
2479 // low-order bytes are recorded
2480 if (nElemSizeVert == 0xFFF0)
2481 nElemSizeVert = 4;
2484 // sanity check that the stream is long enough to fulfill nNumElemVert * nElemSizeVert;
2485 bool bImport = nElemSizeVert && (rIn.remainingSize() / nElemSizeVert >= nNumElemVert);
2486 if (bImport)
2488 aGluePoints.realloc( nNumElemVert );
2489 for (auto& rGluePoint : asNonConstRange(aGluePoints))
2491 sal_Int32 nX(0), nY(0);
2492 if ( nElemSizeVert == 8 )
2494 rIn.ReadInt32( nX )
2495 .ReadInt32( nY );
2497 else
2499 sal_Int16 nTmpA(0), nTmpB(0);
2501 rIn.ReadInt16( nTmpA )
2502 .ReadInt16( nTmpB );
2504 nX = nTmpA;
2505 nY = nTmpB;
2507 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rGluePoint.First, nX );
2508 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( rGluePoint.Second, nY );
2511 aProp.Name = "GluePoints";
2512 aProp.Value <<= aGluePoints;
2513 aPathPropVec.push_back( aProp );
2515 if ( IsProperty( DFF_Prop_connectorType ) )
2517 sal_Int16 nGluePointType = static_cast<sal_uInt16>(GetPropertyValue( DFF_Prop_connectorType, 0 ));
2518 aProp.Name = "GluePointType";
2519 aProp.Value <<= nGluePointType;
2520 aPathPropVec.push_back( aProp );
2522 // pushing the whole Path element
2523 if ( !aPathPropVec.empty() )
2525 aProp.Name = "Path";
2526 aProp.Value <<= comphelper::containerToSequence(aPathPropVec);
2527 aPropVec.push_back( aProp );
2531 // "TextPath" PropertySequence element
2533 bool bTextPathOn = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x4000 ) != 0;
2534 if ( bTextPathOn )
2536 PropVec aTextPathPropVec;
2538 // TextPath
2539 aProp.Name = "TextPath";
2540 aProp.Value <<= bTextPathOn;
2541 aTextPathPropVec.push_back( aProp );
2543 // TextPathMode
2544 bool bTextPathFitPath = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x100 ) != 0;
2546 bool bTextPathFitShape;
2547 if ( IsHardAttribute( DFF_Prop_gtextFStretch ) )
2548 bTextPathFitShape = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x400 ) != 0;
2549 else
2551 bTextPathFitShape = true;
2552 switch( rObjData.eShapeType )
2554 case mso_sptTextArchUpCurve :
2555 case mso_sptTextArchDownCurve :
2556 case mso_sptTextCircleCurve :
2557 case mso_sptTextButtonCurve :
2558 bTextPathFitShape = false;
2559 break;
2560 default : break;
2563 EnhancedCustomShapeTextPathMode eTextPathMode( EnhancedCustomShapeTextPathMode_NORMAL );
2564 if ( bTextPathFitShape )
2565 eTextPathMode = EnhancedCustomShapeTextPathMode_SHAPE;
2566 else if ( bTextPathFitPath )
2567 eTextPathMode = EnhancedCustomShapeTextPathMode_PATH;
2568 aProp.Name = "TextPathMode";
2569 aProp.Value <<= eTextPathMode;
2570 aTextPathPropVec.push_back( aProp );
2572 // ScaleX
2573 bool bTextPathScaleX = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x40 ) != 0;
2574 aProp.Name = "ScaleX";
2575 aProp.Value <<= bTextPathScaleX;
2576 aTextPathPropVec.push_back( aProp );
2577 // SameLetterHeights
2578 bool bSameLetterHeight = ( GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 ) & 0x80 ) != 0;
2579 aProp.Name = "SameLetterHeights";
2580 aProp.Value <<= bSameLetterHeight;
2581 aTextPathPropVec.push_back( aProp );
2583 // pushing the whole TextPath element
2584 aProp.Name = "TextPath";
2585 aProp.Value <<= comphelper::containerToSequence(aTextPathPropVec);
2586 aPropVec.push_back( aProp );
2589 // "AdjustmentValues" // The AdjustmentValues are imported at last, because depending to the type of the
2590 //////////////////////// handle (POLAR) we will convert the adjustment value from a fixed float to double
2592 // checking the last used adjustment handle, so we can determine how many handles are to allocate
2593 sal_uInt32 i = DFF_Prop_adjust10Value;
2594 while ( ( i >= DFF_Prop_adjustValue ) && !IsProperty( i ) )
2595 i--;
2596 sal_Int32 nAdjustmentValues = ( i - DFF_Prop_adjustValue ) + 1;
2597 if ( nAdjustmentValues )
2599 uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentSeq( nAdjustmentValues );
2600 auto pAdjustmentSeq = aAdjustmentSeq.getArray();
2601 while( --nAdjustmentValues >= 0 )
2603 sal_Int32 nValue = 0;
2604 beans::PropertyState ePropertyState = beans::PropertyState_DEFAULT_VALUE;
2605 if ( IsProperty( i ) )
2607 nValue = GetPropertyValue( i, 0 );
2608 ePropertyState = beans::PropertyState_DIRECT_VALUE;
2610 if ( nAdjustmentsWhichNeedsToBeConverted & ( 1 << ( i - DFF_Prop_adjustValue ) ) )
2612 double fValue = nValue;
2613 fValue /= 65536;
2614 pAdjustmentSeq[ nAdjustmentValues ].Value <<= fValue;
2616 else
2617 pAdjustmentSeq[ nAdjustmentValues ].Value <<= nValue;
2618 pAdjustmentSeq[ nAdjustmentValues ].State = ePropertyState;
2619 i--;
2621 aProp.Name = "AdjustmentValues";
2622 aProp.Value <<= aAdjustmentSeq;
2623 aPropVec.push_back( aProp );
2626 // creating the whole property set
2627 rSet.Put( SdrCustomShapeGeometryItem( comphelper::containerToSequence(aPropVec) ) );
2630 void DffPropertyReader::ApplyAttributes( SvStream& rIn, SfxItemSet& rSet ) const
2632 DffRecordHeader aHdTemp;
2633 DffObjData aDffObjTemp( aHdTemp, tools::Rectangle(), 0 );
2634 ApplyAttributes( rIn, rSet, aDffObjTemp );
2637 void DffPropertyReader::ApplyAttributes( SvStream& rIn, SfxItemSet& rSet, DffObjData const & rObjData ) const
2639 bool bHasShadow = false;
2640 bool bNonZeroShadowOffset = false;
2642 if ( IsProperty( DFF_Prop_gtextSize ) )
2643 rSet.Put( SvxFontHeightItem( rManager.ScalePt( GetPropertyValue( DFF_Prop_gtextSize, 0 ) ), 100, EE_CHAR_FONTHEIGHT ) );
2644 sal_uInt32 nFontAttributes = GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 );
2645 if ( nFontAttributes & 0x20 )
2646 rSet.Put( SvxWeightItem( (nFontAttributes & 0x20) ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT ) );
2647 if ( nFontAttributes & 0x10 )
2648 rSet.Put( SvxPostureItem( (nFontAttributes & 0x10) ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC ) );
2649 if ( nFontAttributes & 0x08 )
2650 rSet.Put( SvxUnderlineItem( (nFontAttributes & 0x08) ? LINESTYLE_SINGLE : LINESTYLE_NONE, EE_CHAR_UNDERLINE ) );
2651 if ( nFontAttributes & 0x40 )
2652 rSet.Put( SvxShadowedItem( (nFontAttributes & 0x40) != 0, EE_CHAR_SHADOW ) );
2653 // if ( nFontAttributes & 0x02 )
2654 // rSet.Put( SvxCaseMapItem( nFontAttributes & 0x02 ? SvxCaseMap::SmallCaps : SvxCaseMap::NotMapped ) );
2655 if ( nFontAttributes & 0x01 )
2656 rSet.Put( SvxCrossedOutItem( (nFontAttributes & 0x01) ? STRIKEOUT_SINGLE : STRIKEOUT_NONE, EE_CHAR_STRIKEOUT ) );
2657 if ( IsProperty( DFF_Prop_fillColor ) )
2658 rSet.Put( XFillColorItem( OUString(), rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillColor, 0 ), DFF_Prop_fillColor ) ) );
2659 if ( IsProperty( DFF_Prop_shadowColor ) )
2660 rSet.Put( makeSdrShadowColorItem( rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_shadowColor, 0 ), DFF_Prop_shadowColor ) ) );
2661 else
2663 //The default value for this property is 0x00808080
2664 rSet.Put( makeSdrShadowColorItem( rManager.MSO_CLR_ToColor( 0x00808080, DFF_Prop_shadowColor ) ) );
2666 if ( IsProperty( DFF_Prop_shadowOpacity ) )
2667 rSet.Put( makeSdrShadowTransparenceItem( static_cast<sal_uInt16>( ( 0x10000 - GetPropertyValue( DFF_Prop_shadowOpacity, 0 ) ) / 655 ) ) );
2668 if ( IsProperty( DFF_Prop_shadowOffsetX ) )
2670 sal_Int32 nVal = static_cast< sal_Int32 >( GetPropertyValue( DFF_Prop_shadowOffsetX, 0 ) );
2671 rManager.ScaleEmu( nVal );
2672 rSet.Put( makeSdrShadowXDistItem( nVal ) );
2673 bNonZeroShadowOffset = ( nVal > 0 );
2675 if ( IsProperty( DFF_Prop_shadowOffsetY ) )
2677 sal_Int32 nVal = static_cast< sal_Int32 >( GetPropertyValue( DFF_Prop_shadowOffsetY, 0 ) );
2678 rManager.ScaleEmu( nVal );
2679 rSet.Put( makeSdrShadowYDistItem( nVal ) );
2680 bNonZeroShadowOffset = ( nVal > 0 );
2682 if ( IsProperty( DFF_Prop_fshadowObscured ) )
2684 bHasShadow = ( GetPropertyValue( DFF_Prop_fshadowObscured, 0 ) & 2 ) != 0;
2685 if ( bHasShadow )
2687 if ( !IsProperty( DFF_Prop_shadowOffsetX ) )
2688 rSet.Put( makeSdrShadowXDistItem( 35 ) );
2689 if ( !IsProperty( DFF_Prop_shadowOffsetY ) )
2690 rSet.Put( makeSdrShadowYDistItem( 35 ) );
2693 if ( IsProperty( DFF_Prop_shadowType ) )
2695 auto eShadowType = GetPropertyValue(DFF_Prop_shadowType, 0);
2696 if( eShadowType != mso_shadowOffset && !bNonZeroShadowOffset )
2698 //0.12" == 173 twip == 302 100mm
2699 sal_uInt32 nDist = rManager.pSdrModel->GetScaleUnit() == MapUnit::MapTwip ? 173: 302;
2700 rSet.Put( makeSdrShadowXDistItem( nDist ) );
2701 rSet.Put( makeSdrShadowYDistItem( nDist ) );
2704 if ( bHasShadow )
2706 static bool bCheckShadow(false); // loplugin:constvars:ignore
2708 // #i124477# Found no reason not to set shadow, esp. since it is applied to evtl. existing text
2709 // and will lead to an error if in PPT someone used text and added the object shadow to the
2710 // object carrying that text. I found no cases where this leads to problems (the old bugtracker
2711 // task #160376# from sj is unfortunately no longer available). Keeping the code for now
2712 // to allow easy fallback when this shows problems in the future
2713 if(bCheckShadow)
2715 // #160376# sj: activating shadow only if fill and or linestyle is used
2716 // this is required because of the latest drawing layer core changes.
2717 // #i104085# is related to this.
2718 sal_uInt32 nLineFlags(GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 ));
2719 if(!IsHardAttribute( DFF_Prop_fLine ) && !IsCustomShapeStrokedByDefault( rObjData.eShapeType ))
2720 nLineFlags &= ~0x08;
2721 sal_uInt32 nFillFlags(GetPropertyValue( DFF_Prop_fNoFillHitTest, 0 ));
2722 if(!IsHardAttribute( DFF_Prop_fFilled ) && !IsCustomShapeFilledByDefault( rObjData.eShapeType ))
2723 nFillFlags &= ~0x10;
2724 if ( nFillFlags & 0x10 )
2726 auto eMSO_FillType = GetPropertyValue(DFF_Prop_fillType, mso_fillSolid);
2727 switch( eMSO_FillType )
2729 case mso_fillSolid :
2730 case mso_fillPattern :
2731 case mso_fillTexture :
2732 case mso_fillPicture :
2733 case mso_fillShade :
2734 case mso_fillShadeCenter :
2735 case mso_fillShadeShape :
2736 case mso_fillShadeScale :
2737 case mso_fillShadeTitle :
2738 break;
2739 default:
2740 nFillFlags &=~0x10; // no fillstyle used
2741 break;
2744 if ( ( ( nLineFlags & 0x08 ) == 0 ) && ( ( nFillFlags & 0x10 ) == 0 ) && ( rObjData.eShapeType != mso_sptPictureFrame )) // if there is no fillstyle and linestyle
2745 bHasShadow = false; // we are turning shadow off.
2748 if ( bHasShadow )
2749 rSet.Put( makeSdrShadowItem( bHasShadow ) );
2751 ApplyLineAttributes( rSet, rObjData.eShapeType ); // #i28269#
2752 ApplyFillAttributes( rIn, rSet, rObjData );
2753 if ( rObjData.eShapeType != mso_sptNil || IsProperty( DFF_Prop_pVertices ) )
2755 ApplyCustomShapeGeometryAttributes( rIn, rSet, rObjData );
2756 ApplyCustomShapeTextAttributes( rSet );
2757 if ( rManager.GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_EXCEL )
2759 if ( mnFix16Angle || ( rObjData.nSpFlags & ShapeFlag::FlipV ) )
2760 CheckAndCorrectExcelTextRotation( rIn, rSet, rObjData );
2765 void DffPropertyReader::CheckAndCorrectExcelTextRotation( SvStream& rIn, SfxItemSet& rSet, DffObjData const & rObjData ) const
2767 bool bRotateTextWithShape = rObjData.bRotateTextWithShape;
2768 if ( rObjData.bOpt2 ) // sj: #158494# is the second property set available ? if then we have to check the xml data of
2769 { // the shape, because the textrotation of Excel 2003 and greater versions is stored there
2770 // (upright property of the textbox)
2771 if ( rManager.pSecPropSet->SeekToContent( DFF_Prop_metroBlob, rIn ) )
2773 sal_uInt32 nLen = rManager.pSecPropSet->GetPropertyValue( DFF_Prop_metroBlob, 0 );
2774 if ( nLen )
2776 css::uno::Sequence< sal_Int8 > aXMLDataSeq( nLen );
2777 rIn.ReadBytes(aXMLDataSeq.getArray(), nLen);
2778 css::uno::Reference< css::io::XInputStream > xInputStream
2779 ( new ::comphelper::SequenceInputStream( aXMLDataSeq ) );
2782 css::uno::Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
2783 css::uno::Reference< css::embed::XStorage > xStorage
2784 ( ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream(
2785 OFOPXML_STORAGE_FORMAT_STRING, xInputStream, xContext, true ) );
2786 if ( xStorage.is() )
2788 css::uno::Reference< css::embed::XStorage >
2789 xStorageDRS( xStorage->openStorageElement( "drs", css::embed::ElementModes::SEEKABLEREAD ) );
2790 if ( xStorageDRS.is() )
2792 css::uno::Reference< css::io::XStream > xShapeXMLStream( xStorageDRS->openStreamElement( "shapexml.xml", css::embed::ElementModes::SEEKABLEREAD ) );
2793 if ( xShapeXMLStream.is() )
2795 css::uno::Reference< css::io::XInputStream > xShapeXMLInputStream( xShapeXMLStream->getInputStream() );
2796 if ( xShapeXMLInputStream.is() )
2798 css::uno::Sequence< sal_Int8 > aSeq;
2799 sal_Int32 nBytesRead = xShapeXMLInputStream->readBytes( aSeq, 0x7fffffff );
2800 if ( nBytesRead )
2801 { // for only one property I spare to use a XML parser at this point, this
2802 // should be enhanced if needed
2804 bRotateTextWithShape = true; // using the correct xml default
2805 const char* pArry = reinterpret_cast< char* >( aSeq.getArray() );
2806 const char* const pUpright = "upright=";
2807 const char* pEnd = pArry + nBytesRead;
2808 const char* pPtr = pArry;
2809 while( ( pPtr + 12 ) < pEnd )
2811 if ( !memcmp( pUpright, pPtr, 8 ) )
2813 bRotateTextWithShape = ( pPtr[ 9 ] != '1' ) && ( pPtr[ 9 ] != 't' );
2814 break;
2816 else
2817 pPtr++;
2825 catch( css::uno::Exception& )
2831 if ( bRotateTextWithShape )
2832 return;
2834 const css::uno::Any* pAny;
2835 SdrCustomShapeGeometryItem aGeometryItem(rSet.Get( SDRATTR_CUSTOMSHAPE_GEOMETRY ));
2836 static const OUStringLiteral sTextRotateAngle( u"TextRotateAngle" );
2837 pAny = aGeometryItem.GetPropertyValueByName( sTextRotateAngle );
2838 double fExtraTextRotateAngle = 0.0;
2839 if ( pAny )
2840 *pAny >>= fExtraTextRotateAngle;
2842 if ( rManager.mnFix16Angle )
2843 fExtraTextRotateAngle += toDegrees(mnFix16Angle);
2844 if ( rObjData.nSpFlags & ShapeFlag::FlipV )
2845 fExtraTextRotateAngle -= 180.0;
2847 css::beans::PropertyValue aTextRotateAngle;
2848 aTextRotateAngle.Name = sTextRotateAngle;
2849 aTextRotateAngle.Value <<= fExtraTextRotateAngle;
2850 aGeometryItem.SetPropertyValue( aTextRotateAngle );
2851 rSet.Put( aGeometryItem );
2855 void DffPropertyReader::ImportGradientColor( SfxItemSet& aSet, sal_uInt32 eMSO_FillType, double dTrans , double dBackTrans) const
2857 //MS Focus prop will impact the start and end color position. And AOO does not
2858 //support this prop. So need some swap for the two color to keep fidelity with AOO and MS shape.
2859 //So below var is defined.
2860 sal_Int32 nChgColors = 0;
2861 sal_Int32 nAngleFix16 = GetPropertyValue( DFF_Prop_fillAngle, 0 );
2862 if(nAngleFix16 >= 0)
2863 nChgColors ^= 1;
2865 //Translate a MS clockwise(+) or count clockwise angle(-) into an AOO count clock wise angle
2866 Degree10 nAngle( 3600_deg10 - to<Degree10>( Fix16ToAngle(nAngleFix16) ) );
2867 //Make sure this angle belongs to 0~3600
2868 while ( nAngle >= 3600_deg10 ) nAngle -= 3600_deg10;
2869 while ( nAngle < 0_deg10 ) nAngle += 3600_deg10;
2871 //Rotate angle
2872 if ( mbRotateGranientFillWithAngle )
2874 sal_Int32 nRotateAngle = GetPropertyValue( DFF_Prop_Rotation, 0 );
2875 //nAngle is a clockwise angle. If nRotateAngle is a clockwise angle, then gradient needs to be rotated a little less
2876 //or it needs to be rotated a little more
2877 nAngle -= to<Degree10>(Fix16ToAngle(nRotateAngle));
2879 while ( nAngle >= 3600_deg10 ) nAngle -= 3600_deg10;
2880 while ( nAngle < 0_deg10 ) nAngle += 3600_deg10;
2882 css::awt::GradientStyle eGrad = css::awt::GradientStyle_LINEAR;
2884 sal_Int32 nFocus = GetPropertyValue( DFF_Prop_fillFocus, 0 );
2885 if ( !nFocus )
2886 nChgColors ^= 1;
2887 else if ( nFocus < 0 )//If it is a negative focus, the color will be swapped
2889 nFocus = o3tl::saturating_toggle_sign(nFocus);
2890 nChgColors ^= 1;
2893 if( nFocus > 40 && nFocus < 60 )
2895 eGrad = css::awt::GradientStyle_AXIAL;//A axial gradient other than linear
2896 nChgColors ^= 1;
2898 //if the type is linear or axial, just save focus to nFocusX and nFocusY for export
2899 //Core function does no need them. They serve for rect gradient(CenterXY).
2900 sal_uInt16 nFocusX = static_cast<sal_uInt16>(nFocus);
2901 sal_uInt16 nFocusY = static_cast<sal_uInt16>(nFocus);
2903 switch( eMSO_FillType )
2905 case mso_fillShadeShape :
2907 eGrad = css::awt::GradientStyle_RECT;
2908 nFocusY = nFocusX = 50;
2909 nChgColors ^= 1;
2911 break;
2912 case mso_fillShadeCenter :
2914 eGrad = css::awt::GradientStyle_RECT;
2915 //A MS fillTo prop specifies the relative position of the left boundary
2916 //of the center rectangle in a concentric shaded fill. Use 100 or 0 to keep fidelity
2917 nFocusX=(GetPropertyValue( DFF_Prop_fillToRight, 0 )==0x10000) ? 100 : 0;
2918 nFocusY=(GetPropertyValue( DFF_Prop_fillToBottom,0 )==0x10000) ? 100 : 0;
2919 nChgColors ^= 1;
2921 break;
2922 default: break;
2925 Color aCol1( rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillColor ) );
2926 Color aCol2( rManager.MSO_CLR_ToColor( GetPropertyValue( DFF_Prop_fillBackColor, sal_uInt32(COL_WHITE) ), DFF_Prop_fillBackColor ) );
2927 if ( nChgColors )
2929 //Swap start and end color
2930 Color aZwi( aCol1 );
2931 aCol1 = aCol2;
2932 aCol2 = aZwi;
2933 //Swap two colors' transparency
2934 std::swap( dTrans, dBackTrans );
2937 //Construct gradient item
2938 basegfx::BGradient aGrad(
2939 basegfx::BColorStops(aCol2.getBColor(), aCol1.getBColor()),
2940 eGrad, nAngle, nFocusX, nFocusY );
2941 //Intensity has been merged into color. So here just set is as 100
2942 aGrad.SetStartIntens( 100 );
2943 aGrad.SetEndIntens( 100 );
2944 aSet.Put( XFillGradientItem( OUString(), aGrad ) );
2945 //Construct transparency item. This item can coordinate with both solid and gradient.
2946 if ( dTrans < 1.0 || dBackTrans < 1.0 )
2948 sal_uInt8 nStartCol = static_cast<sal_uInt8>( (1 - dTrans )* 255 );
2949 sal_uInt8 nEndCol = static_cast<sal_uInt8>( ( 1- dBackTrans ) * 255 );
2950 aCol1 = Color(nStartCol, nStartCol, nStartCol);
2951 aCol2 = Color(nEndCol, nEndCol, nEndCol);
2953 basegfx::BGradient aGrad2(
2954 basegfx::BColorStops(aCol2.getBColor(), aCol1.getBColor()),
2955 eGrad, nAngle, nFocusX, nFocusY );
2956 aSet.Put( XFillFloatTransparenceItem( OUString(), aGrad2 ) );
2961 //- Record Manager ----------------------------------------------------------
2964 DffRecordList::DffRecordList( DffRecordList* pList ) :
2965 nCount ( 0 ),
2966 nCurrent ( 0 ),
2967 pPrev ( pList )
2969 if ( pList )
2970 pList->pNext.reset( this );
2973 DffRecordList::~DffRecordList()
2977 DffRecordManager::DffRecordManager() :
2978 DffRecordList ( nullptr ),
2979 pCList ( static_cast<DffRecordList*>(this) )
2983 DffRecordManager::DffRecordManager( SvStream& rIn ) :
2984 DffRecordList ( nullptr ),
2985 pCList ( static_cast<DffRecordList*>(this) )
2987 Consume( rIn );
2990 void DffRecordManager::Consume( SvStream& rIn, sal_uInt32 nStOfs )
2992 Clear();
2993 sal_uInt64 nOldPos = rIn.Tell();
2994 if ( !nStOfs )
2996 DffRecordHeader aHd;
2997 bool bOk = ReadDffRecordHeader( rIn, aHd );
2998 if (bOk && aHd.nRecVer == DFF_PSFLAG_CONTAINER)
2999 nStOfs = aHd.GetRecEndFilePos();
3001 if ( !nStOfs )
3002 return;
3004 pCList = this;
3005 while ( pCList->pNext )
3006 pCList = pCList->pNext.get();
3007 while (rIn.good() && ( ( rIn.Tell() + 8 ) <= nStOfs ))
3009 if ( pCList->nCount == DFF_RECORD_MANAGER_BUF_SIZE )
3010 pCList = new DffRecordList( pCList );
3011 if (!ReadDffRecordHeader(rIn, pCList->mHd[ pCList->nCount ]))
3012 break;
3013 bool bSeekSucceeded = pCList->mHd[ pCList->nCount++ ].SeekToEndOfRecord(rIn);
3014 if (!bSeekSucceeded)
3015 break;
3017 rIn.Seek( nOldPos );
3020 void DffRecordManager::Clear()
3022 pCList = this;
3023 pNext.reset();
3024 nCurrent = 0;
3025 nCount = 0;
3028 DffRecordHeader* DffRecordManager::Current()
3030 DffRecordHeader* pRet = nullptr;
3031 if ( pCList->nCurrent < pCList->nCount )
3032 pRet = &pCList->mHd[ pCList->nCurrent ];
3033 return pRet;
3036 DffRecordHeader* DffRecordManager::First()
3038 DffRecordHeader* pRet = nullptr;
3039 pCList = this;
3040 if ( pCList->nCount )
3042 pCList->nCurrent = 0;
3043 pRet = &pCList->mHd[ 0 ];
3045 return pRet;
3048 DffRecordHeader* DffRecordManager::Next()
3050 DffRecordHeader* pRet = nullptr;
3051 sal_uInt32 nC = pCList->nCurrent + 1;
3052 if ( nC < pCList->nCount )
3054 pCList->nCurrent++;
3055 pRet = &pCList->mHd[ nC ];
3057 else if ( pCList->pNext )
3059 pCList = pCList->pNext.get();
3060 pCList->nCurrent = 0;
3061 pRet = &pCList->mHd[ 0 ];
3063 return pRet;
3066 DffRecordHeader* DffRecordManager::Prev()
3068 DffRecordHeader* pRet = nullptr;
3069 sal_uInt32 nCur = pCList->nCurrent;
3070 if ( !nCur && pCList->pPrev )
3072 pCList = pCList->pPrev;
3073 nCur = pCList->nCount;
3075 if ( nCur-- )
3077 pCList->nCurrent = nCur;
3078 pRet = &pCList->mHd[ nCur ];
3080 return pRet;
3083 DffRecordHeader* DffRecordManager::Last()
3085 DffRecordHeader* pRet = nullptr;
3086 while ( pCList->pNext )
3087 pCList = pCList->pNext.get();
3088 sal_uInt32 nCnt = pCList->nCount;
3089 if ( nCnt-- )
3091 pCList->nCurrent = nCnt;
3092 pRet = &pCList->mHd[ nCnt ];
3094 return pRet;
3097 bool DffRecordManager::SeekToContent( SvStream& rIn, sal_uInt16 nRecId, DffSeekToContentMode eMode )
3099 DffRecordHeader* pHd = GetRecordHeader( nRecId, eMode );
3100 if ( pHd )
3102 pHd->SeekToContent( rIn );
3103 return true;
3105 else
3106 return false;
3109 DffRecordHeader* DffRecordManager::GetRecordHeader( sal_uInt16 nRecId, DffSeekToContentMode eMode )
3111 sal_uInt32 nOldCurrent = pCList->nCurrent;
3112 DffRecordList* pOldList = pCList;
3113 DffRecordHeader* pHd;
3115 if ( eMode == SEEK_FROM_BEGINNING )
3116 pHd = First();
3117 else
3118 pHd = Next();
3120 while ( pHd )
3122 if ( pHd->nRecType == nRecId )
3123 break;
3124 pHd = Next();
3126 if ( !pHd && eMode == SEEK_FROM_CURRENT_AND_RESTART )
3128 DffRecordHeader* pBreak = &pOldList->mHd[ nOldCurrent ];
3129 pHd = First();
3130 if ( pHd )
3132 while ( pHd != pBreak )
3134 if ( pHd->nRecType == nRecId )
3135 break;
3136 pHd = Next();
3138 if ( pHd->nRecType != nRecId )
3139 pHd = nullptr;
3142 if ( !pHd )
3144 pCList = pOldList;
3145 pOldList->nCurrent = nOldCurrent;
3147 return pHd;
3151 // private methods
3154 bool CompareSvxMSDffShapeInfoById::operator() (
3155 std::shared_ptr<SvxMSDffShapeInfo> const& lhs,
3156 std::shared_ptr<SvxMSDffShapeInfo> const& rhs) const
3158 return lhs->nShapeId < rhs->nShapeId;
3161 bool CompareSvxMSDffShapeInfoByTxBxComp::operator() (
3162 std::shared_ptr<SvxMSDffShapeInfo> const& lhs,
3163 std::shared_ptr<SvxMSDffShapeInfo> const& rhs) const
3165 return lhs->nTxBxComp < rhs->nTxBxComp;
3168 void SvxMSDffManager::Scale( sal_Int32& rVal ) const
3170 if ( bNeedMap )
3172 if (rVal > nMaxAllowedVal)
3174 SAL_WARN("filter.ms", "Cannot scale value: " << rVal);
3175 rVal = SAL_MAX_INT32;
3176 return;
3178 else if (rVal < nMinAllowedVal)
3180 SAL_WARN("filter.ms", "Cannot scale value: " << rVal);
3181 rVal = SAL_MAX_INT32;
3182 return;
3185 rVal = BigMulDiv( rVal, nMapMul, nMapDiv );
3189 void SvxMSDffManager::Scale( Point& rPos ) const
3191 rPos.AdjustX(nMapXOfs );
3192 rPos.AdjustY(nMapYOfs );
3193 if ( bNeedMap )
3195 rPos.setX( BigMulDiv( rPos.X(), nMapMul, nMapDiv ) );
3196 rPos.setY( BigMulDiv( rPos.Y(), nMapMul, nMapDiv ) );
3200 void SvxMSDffManager::Scale( Size& rSiz ) const
3202 if ( bNeedMap )
3204 rSiz.setWidth( BigMulDiv( rSiz.Width(), nMapMul, nMapDiv ) );
3205 rSiz.setHeight( BigMulDiv( rSiz.Height(), nMapMul, nMapDiv ) );
3209 void SvxMSDffManager::ScaleEmu( sal_Int32& rVal ) const
3211 rVal = BigMulDiv( rVal, nEmuMul, nEmuDiv );
3214 sal_uInt32 SvxMSDffManager::ScalePt( sal_uInt32 nVal ) const
3216 MapUnit eMap = pSdrModel->GetScaleUnit();
3217 Fraction aFact( GetMapFactor( MapUnit::MapPoint, eMap ).X() );
3218 tools::Long aMul = aFact.GetNumerator();
3219 tools::Long aDiv = aFact.GetDenominator() * 65536;
3220 aFact = Fraction( aMul, aDiv ); // try again to shorten it
3221 return BigMulDiv( nVal, aFact.GetNumerator(), aFact.GetDenominator() );
3224 sal_Int32 SvxMSDffManager::ScalePoint( sal_Int32 nVal ) const
3226 return BigMulDiv( nVal, nPntMul, nPntDiv );
3229 void SvxMSDffManager::SetModel(SdrModel* pModel, tools::Long nApplicationScale)
3231 pSdrModel = pModel;
3232 if( pModel && (0 < nApplicationScale) )
3234 // PPT works in units of 576DPI
3235 // WW on the other side uses twips, i.e. 1440DPI.
3236 MapUnit eMap = pSdrModel->GetScaleUnit();
3237 Fraction aFact( GetMapFactor(MapUnit::MapInch, eMap).X() );
3238 tools::Long nMul=aFact.GetNumerator();
3239 tools::Long nDiv=aFact.GetDenominator()*nApplicationScale;
3240 aFact=Fraction(nMul,nDiv); // try again to shorten it
3241 // For 100TH_MM -> 2540/576=635/144
3242 // For Twip -> 1440/576=5/2
3243 nMapMul = aFact.GetNumerator();
3244 nMapDiv = aFact.GetDenominator();
3245 bNeedMap = nMapMul!=nMapDiv;
3247 // MS-DFF-Properties are mostly given in EMU (English Metric Units)
3248 // 1mm=36000emu, 1twip=635emu
3249 aFact=GetMapFactor(MapUnit::Map100thMM,eMap).X();
3250 nMul=aFact.GetNumerator();
3251 nDiv=aFact.GetDenominator()*360;
3252 aFact=Fraction(nMul,nDiv); // try again to shorten it
3253 // For 100TH_MM -> 1/360
3254 // For Twip -> 14,40/(25,4*360)=144/91440=1/635
3255 nEmuMul=aFact.GetNumerator();
3256 nEmuDiv=aFact.GetDenominator();
3258 // And something for typographic Points
3259 aFact=GetMapFactor(MapUnit::MapPoint,eMap).X();
3260 nPntMul=aFact.GetNumerator();
3261 nPntDiv=aFact.GetDenominator();
3263 else
3265 pModel = nullptr;
3266 nMapMul = nMapDiv = nMapXOfs = nMapYOfs = nEmuMul = nEmuDiv = nPntMul = nPntDiv = 0;
3267 bNeedMap = false;
3270 if (bNeedMap)
3272 assert(nMapMul > nMapDiv);
3274 BigInt aMinVal(SAL_MIN_INT32);
3275 aMinVal /= nMapMul;
3276 aMinVal *= nMapDiv;
3277 nMinAllowedVal = aMinVal;
3279 BigInt aMaxVal(SAL_MAX_INT32);
3280 aMaxVal /= nMapMul;
3281 aMaxVal *= nMapDiv;
3282 nMaxAllowedVal = aMaxVal;
3284 else
3286 nMinAllowedVal = SAL_MIN_INT32;
3287 nMaxAllowedVal = SAL_MAX_INT32;
3291 bool SvxMSDffManager::SeekToShape( SvStream& rSt, SvxMSDffClientData* /* pClientData */, sal_uInt32 nId ) const
3293 bool bRet = false;
3294 if ( !maFidcls.empty() )
3296 sal_uInt64 nOldPos = rSt.Tell();
3297 sal_uInt32 nSec = ( nId >> 10 ) - 1;
3298 if ( nSec < mnIdClusters )
3300 OffsetMap::const_iterator it = maDgOffsetTable.find( maFidcls[ nSec ].dgid );
3301 if ( it != maDgOffsetTable.end() )
3303 sal_uInt64 nOfs = it->second;
3304 rSt.Seek( nOfs );
3305 DffRecordHeader aEscherF002Hd;
3306 bool bOk = ReadDffRecordHeader( rSt, aEscherF002Hd );
3307 sal_uLong nEscherF002End = bOk ? aEscherF002Hd.GetRecEndFilePos() : 0;
3308 while (rSt.good() && rSt.Tell() < nEscherF002End)
3310 DffRecordHeader aEscherObjListHd;
3311 if (!ReadDffRecordHeader(rSt, aEscherObjListHd))
3312 break;
3313 if ( aEscherObjListHd.nRecVer != 0xf )
3315 bool bSeekSuccess = aEscherObjListHd.SeekToEndOfRecord(rSt);
3316 if (!bSeekSuccess)
3317 break;
3319 else if ( aEscherObjListHd.nRecType == DFF_msofbtSpContainer )
3321 DffRecordHeader aShapeHd;
3322 if ( SeekToRec( rSt, DFF_msofbtSp, aEscherObjListHd.GetRecEndFilePos(), &aShapeHd ) )
3324 sal_uInt32 nShapeId(0);
3325 rSt.ReadUInt32( nShapeId );
3326 if ( nId == nShapeId )
3328 aEscherObjListHd.SeekToBegOfRecord( rSt );
3329 bRet = true;
3330 break;
3333 bool bSeekSuccess = aEscherObjListHd.SeekToEndOfRecord(rSt);
3334 if (!bSeekSuccess)
3335 break;
3340 if ( !bRet )
3341 rSt.Seek( nOldPos );
3343 return bRet;
3346 bool SvxMSDffManager::SeekToRec( SvStream& rSt, sal_uInt16 nRecId, sal_uLong nMaxFilePos, DffRecordHeader* pRecHd, sal_uLong nSkipCount )
3348 bool bRet = false;
3349 sal_uInt64 nOldFPos = rSt.Tell(); // store FilePos to restore it later if necessary
3352 DffRecordHeader aHd;
3353 if (!ReadDffRecordHeader(rSt, aHd))
3354 break;
3355 if (aHd.nRecLen > nMaxLegalDffRecordLength)
3356 break;
3357 if ( aHd.nRecType == nRecId )
3359 if ( nSkipCount )
3360 nSkipCount--;
3361 else
3363 bRet = true;
3364 if ( pRecHd != nullptr )
3365 *pRecHd = aHd;
3366 else
3368 bool bSeekSuccess = aHd.SeekToBegOfRecord(rSt);
3369 if (!bSeekSuccess)
3371 bRet = false;
3372 break;
3377 if ( !bRet )
3379 bool bSeekSuccess = aHd.SeekToEndOfRecord(rSt);
3380 if (!bSeekSuccess)
3381 break;
3384 while ( rSt.good() && rSt.Tell() < nMaxFilePos && !bRet );
3385 if ( !bRet )
3386 rSt.Seek( nOldFPos ); // restore original FilePos
3387 return bRet;
3390 bool SvxMSDffManager::SeekToRec2( sal_uInt16 nRecId1, sal_uInt16 nRecId2, sal_uLong nMaxFilePos ) const
3392 bool bRet = false;
3393 sal_uInt64 nOldFPos = rStCtrl.Tell(); // remember FilePos for conditionally later restoration
3396 DffRecordHeader aHd;
3397 if (!ReadDffRecordHeader(rStCtrl, aHd))
3398 break;
3399 if ( aHd.nRecType == nRecId1 || aHd.nRecType == nRecId2 )
3401 bRet = true;
3402 bool bSeekSuccess = aHd.SeekToBegOfRecord(rStCtrl);
3403 if (!bSeekSuccess)
3405 bRet = false;
3406 break;
3409 if ( !bRet )
3411 bool bSeekSuccess = aHd.SeekToEndOfRecord(rStCtrl);
3412 if (!bSeekSuccess)
3413 break;
3416 while ( rStCtrl.good() && rStCtrl.Tell() < nMaxFilePos && !bRet );
3417 if ( !bRet )
3418 rStCtrl.Seek( nOldFPos ); // restore FilePos
3419 return bRet;
3423 bool SvxMSDffManager::GetColorFromPalette( sal_uInt16 /* nNum */, Color& rColor ) const
3425 // This method has to be overwritten in the class
3426 // derived for the excel export
3427 rColor = COL_WHITE;
3428 return true;
3431 // sj: the documentation is not complete, especially in ppt the normal rgb for text
3432 // color is written as 0xfeRRGGBB, this can't be explained by the documentation, nearly
3433 // every bit in the upper code is set -> so there seems to be a special handling for
3434 // ppt text colors, i decided not to fix this in MSO_CLR_ToColor because of possible
3435 // side effects, instead MSO_TEXT_CLR_ToColor is called for PPT text colors, to map
3436 // the color code to something that behaves like the other standard color codes used by
3437 // fill and line color
3438 Color SvxMSDffManager::MSO_TEXT_CLR_ToColor( sal_uInt32 nColorCode ) const
3440 // for text colors: Header is 0xfeRRGGBB
3441 if ( ( nColorCode & 0xfe000000 ) == 0xfe000000 )
3442 nColorCode &= 0x00ffffff;
3443 else
3445 // for colorscheme colors the color index are the lower three bits of the upper byte
3446 if ( ( nColorCode & 0xf8000000 ) == 0 ) // this must be a colorscheme index
3448 nColorCode >>= 24;
3449 nColorCode |= 0x8000000;
3452 return MSO_CLR_ToColor( nColorCode );
3455 Color SvxMSDffManager::MSO_CLR_ToColor( sal_uInt32 nColorCode, sal_uInt16 nContentProperty ) const
3457 Color aColor( mnDefaultColor );
3459 // for text colors: Header is 0xfeRRGGBB
3460 if ( ( nColorCode & 0xfe000000 ) == 0xfe000000 ) // sj: it needs to be checked if 0xfe is used in
3461 nColorCode &= 0x00ffffff; // other cases than ppt text -> if not this code can be removed
3463 sal_uInt8 nUpper = static_cast<sal_uInt8>( nColorCode >> 24 );
3465 // sj: below change from 0x1b to 0x19 was done because of i84812 (0x02 -> rgb color),
3466 // now I have some problems to fix i104685 (there the color value is 0x02000000 which requires
3467 // a 0x2 scheme color to be displayed properly), the color docu seems to be incomplete
3468 if( nUpper & 0x19 ) // if( nUpper & 0x1f )
3470 if( ( nUpper & 0x08 ) || ( ( nUpper & 0x10 ) == 0 ) )
3472 // SCHEMECOLOR
3473 if ( !GetColorFromPalette( ( nUpper & 8 ) ? static_cast<sal_uInt16>(nColorCode) : nUpper, aColor ) )
3475 switch( nContentProperty )
3477 case DFF_Prop_pictureTransparent :
3478 case DFF_Prop_shadowColor :
3479 case DFF_Prop_fillBackColor :
3480 case DFF_Prop_fillColor :
3481 aColor = COL_WHITE;
3482 break;
3483 case DFF_Prop_lineColor :
3485 aColor = COL_BLACK;
3487 break;
3491 else // SYSCOLOR
3493 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
3495 sal_uInt16 nParameter = sal_uInt16(( nColorCode >> 16 ) & 0x00ff); // the HiByte of nParameter is not zero, an exclusive AND is helping :o
3496 sal_uInt16 nFunctionBits = static_cast<sal_uInt16>( ( nColorCode & 0x00000f00 ) >> 8 );
3497 sal_uInt16 nAdditionalFlags = static_cast<sal_uInt16>( ( nColorCode & 0x0000f000) >> 8 );
3498 sal_uInt16 nColorIndex = sal_uInt16(nColorCode & 0x00ff);
3499 sal_uInt32 nPropColor = 0;
3501 sal_uInt16 nCProp = 0;
3503 switch ( nColorIndex )
3505 case mso_syscolorButtonFace : aColor = rStyleSettings.GetFaceColor(); break;
3506 case mso_syscolorWindowText : aColor = rStyleSettings.GetWindowTextColor(); break;
3507 case mso_syscolorMenu : aColor = rStyleSettings.GetMenuColor(); break;
3508 case mso_syscolor3DLight :
3509 case mso_syscolorButtonHighlight :
3510 case mso_syscolorHighlight : aColor = rStyleSettings.GetHighlightColor(); break;
3511 case mso_syscolorHighlightText : aColor = rStyleSettings.GetHighlightTextColor(); break;
3512 case mso_syscolorCaptionText : aColor = rStyleSettings.GetMenuTextColor(); break;
3513 case mso_syscolorActiveCaption : aColor = rStyleSettings.GetHighlightColor(); break;
3514 case mso_syscolorButtonShadow : aColor = rStyleSettings.GetShadowColor(); break;
3515 case mso_syscolorButtonText : aColor = rStyleSettings.GetButtonTextColor(); break;
3516 case mso_syscolorGrayText : aColor = rStyleSettings.GetDeactiveColor(); break;
3517 case mso_syscolorInactiveCaption : aColor = rStyleSettings.GetDeactiveColor(); break;
3518 case mso_syscolorInactiveCaptionText : aColor = rStyleSettings.GetDeactiveColor(); break;
3519 case mso_syscolorInfoBackground : aColor = rStyleSettings.GetFaceColor(); break;
3520 case mso_syscolorInfoText : aColor = rStyleSettings.GetLabelTextColor(); break;
3521 case mso_syscolorMenuText : aColor = rStyleSettings.GetMenuTextColor(); break;
3522 case mso_syscolorScrollbar : aColor = rStyleSettings.GetFaceColor(); break;
3523 case mso_syscolorWindow : aColor = rStyleSettings.GetWindowColor(); break;
3524 case mso_syscolorWindowFrame : aColor = rStyleSettings.GetWindowColor(); break;
3526 case mso_colorFillColor :
3528 nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff );
3529 nCProp = DFF_Prop_fillColor;
3531 break;
3532 case mso_colorLineOrFillColor : // ( use the line color only if there is a line )
3534 if ( GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 ) & 8 )
3536 nPropColor = GetPropertyValue( DFF_Prop_lineColor, 0 );
3537 nCProp = DFF_Prop_lineColor;
3539 else
3541 nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff );
3542 nCProp = DFF_Prop_fillColor;
3545 break;
3546 case mso_colorLineColor :
3548 nPropColor = GetPropertyValue( DFF_Prop_lineColor, 0 );
3549 nCProp = DFF_Prop_lineColor;
3551 break;
3552 case mso_colorShadowColor :
3554 nPropColor = GetPropertyValue( DFF_Prop_shadowColor, 0x808080 );
3555 nCProp = DFF_Prop_shadowColor;
3557 break;
3558 case mso_colorThis : // ( use this color ... )
3560 nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff ); //?????????????
3561 nCProp = DFF_Prop_fillColor;
3563 break;
3564 case mso_colorFillBackColor :
3566 nPropColor = GetPropertyValue( DFF_Prop_fillBackColor, 0xffffff );
3567 nCProp = DFF_Prop_fillBackColor;
3569 break;
3570 case mso_colorLineBackColor :
3572 nPropColor = GetPropertyValue( DFF_Prop_lineBackColor, 0xffffff );
3573 nCProp = DFF_Prop_lineBackColor;
3575 break;
3576 case mso_colorFillThenLine : // ( use the fillcolor unless no fill and line )
3578 nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff ); //?????????????
3579 nCProp = DFF_Prop_fillColor;
3581 break;
3582 case mso_colorIndexMask : // ( extract the color index ) ?
3584 nPropColor = GetPropertyValue( DFF_Prop_fillColor, 0xffffff ); //?????????????
3585 nCProp = DFF_Prop_fillColor;
3587 break;
3589 if ( nCProp && ( nPropColor & 0x10000000 ) == 0 ) // beware of looping recursive
3590 aColor = MSO_CLR_ToColor( nPropColor, nCProp );
3592 if( nAdditionalFlags & 0x80 ) // make color gray
3594 sal_uInt8 nZwi = aColor.GetLuminance();
3595 aColor = Color( nZwi, nZwi, nZwi );
3597 switch( nFunctionBits )
3599 case 0x01 : // darken color by parameter
3601 aColor.SetRed( sal::static_int_cast< sal_uInt8 >( ( nParameter * aColor.GetRed() ) >> 8 ) );
3602 aColor.SetGreen( sal::static_int_cast< sal_uInt8 >( ( nParameter * aColor.GetGreen() ) >> 8 ) );
3603 aColor.SetBlue( sal::static_int_cast< sal_uInt8 >( ( nParameter * aColor.GetBlue() ) >> 8 ) );
3605 break;
3606 case 0x02 : // lighten color by parameter
3608 sal_uInt16 nInvParameter = ( 0x00ff - nParameter ) * 0xff;
3609 aColor.SetRed( sal::static_int_cast< sal_uInt8 >( ( nInvParameter + ( nParameter * aColor.GetRed() ) ) >> 8 ) );
3610 aColor.SetGreen( sal::static_int_cast< sal_uInt8 >( ( nInvParameter + ( nParameter * aColor.GetGreen() ) ) >> 8 ) );
3611 aColor.SetBlue( sal::static_int_cast< sal_uInt8 >( ( nInvParameter + ( nParameter * aColor.GetBlue() ) ) >> 8 ) );
3613 break;
3614 case 0x03 : // add grey level RGB(p,p,p)
3616 sal_Int16 nR = static_cast<sal_Int16>(aColor.GetRed()) + static_cast<sal_Int16>(nParameter);
3617 sal_Int16 nG = static_cast<sal_Int16>(aColor.GetGreen()) + static_cast<sal_Int16>(nParameter);
3618 sal_Int16 nB = static_cast<sal_Int16>(aColor.GetBlue()) + static_cast<sal_Int16>(nParameter);
3619 if ( nR > 0x00ff )
3620 nR = 0x00ff;
3621 if ( nG > 0x00ff )
3622 nG = 0x00ff;
3623 if ( nB > 0x00ff )
3624 nB = 0x00ff;
3625 aColor = Color( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
3627 break;
3628 case 0x04 : // subtract grey level RGB(p,p,p)
3630 sal_Int16 nR = static_cast<sal_Int16>(aColor.GetRed()) - static_cast<sal_Int16>(nParameter);
3631 sal_Int16 nG = static_cast<sal_Int16>(aColor.GetGreen()) - static_cast<sal_Int16>(nParameter);
3632 sal_Int16 nB = static_cast<sal_Int16>(aColor.GetBlue()) - static_cast<sal_Int16>(nParameter);
3633 if ( nR < 0 )
3634 nR = 0;
3635 if ( nG < 0 )
3636 nG = 0;
3637 if ( nB < 0 )
3638 nB = 0;
3639 aColor = Color( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
3641 break;
3642 case 0x05 : // subtract from gray level RGB(p,p,p)
3644 sal_Int16 nR = static_cast<sal_Int16>(nParameter) - static_cast<sal_Int16>(aColor.GetRed());
3645 sal_Int16 nG = static_cast<sal_Int16>(nParameter) - static_cast<sal_Int16>(aColor.GetGreen());
3646 sal_Int16 nB = static_cast<sal_Int16>(nParameter) - static_cast<sal_Int16>(aColor.GetBlue());
3647 if ( nR < 0 )
3648 nR = 0;
3649 if ( nG < 0 )
3650 nG = 0;
3651 if ( nB < 0 )
3652 nB = 0;
3653 aColor = Color( static_cast<sal_uInt8>(nR), static_cast<sal_uInt8>(nG), static_cast<sal_uInt8>(nB) );
3655 break;
3656 case 0x06 : // per component: black if < p, white if >= p
3658 aColor.SetRed( aColor.GetRed() < nParameter ? 0x00 : 0xff );
3659 aColor.SetGreen( aColor.GetGreen() < nParameter ? 0x00 : 0xff );
3660 aColor.SetBlue( aColor.GetBlue() < nParameter ? 0x00 : 0xff );
3662 break;
3664 if ( nAdditionalFlags & 0x40 ) // top-bit invert
3665 aColor = Color( aColor.GetRed() ^ 0x80, aColor.GetGreen() ^ 0x80, aColor.GetBlue() ^ 0x80 );
3667 if ( nAdditionalFlags & 0x20 ) // invert color
3668 aColor = Color(0xff - aColor.GetRed(), 0xff - aColor.GetGreen(), 0xff - aColor.GetBlue());
3671 else if ( ( nUpper & 4 ) && ( ( nColorCode & 0xfffff8 ) == 0 ) )
3672 { // case of nUpper == 4 powerpoint takes this as argument for a colorschemecolor
3673 GetColorFromPalette( nUpper, aColor );
3675 else // attributed hard, maybe with hint to SYSTEMRGB
3676 aColor = Color( static_cast<sal_uInt8>(nColorCode), static_cast<sal_uInt8>( nColorCode >> 8 ), static_cast<sal_uInt8>( nColorCode >> 16 ) );
3677 return aColor;
3680 void SvxMSDffManager::ReadObjText( SvStream& rStream, SdrObject* pObj )
3682 DffRecordHeader aRecHd;
3683 if (!ReadDffRecordHeader(rStream, aRecHd))
3684 return;
3685 if( aRecHd.nRecType != DFF_msofbtClientTextbox && aRecHd.nRecType != 0x1022 )
3686 return;
3688 while (rStream.good() && rStream.Tell() < aRecHd.GetRecEndFilePos())
3690 DffRecordHeader aHd;
3691 if (!ReadDffRecordHeader(rStream, aHd))
3692 break;
3693 switch( aHd.nRecType )
3695 case DFF_PST_TextBytesAtom:
3696 case DFF_PST_TextCharsAtom:
3698 bool bUniCode = ( aHd.nRecType == DFF_PST_TextCharsAtom );
3699 sal_uInt32 nBytes = aHd.nRecLen;
3700 OUString aStr = MSDFFReadZString( rStream, nBytes, bUniCode );
3701 ReadObjText( aStr, pObj );
3703 break;
3704 default:
3705 break;
3707 bool bSeekSuccess = aHd.SeekToEndOfRecord(rStream);
3708 if (!bSeekSuccess)
3709 break;
3713 // sj: I just want to set a string for a text object that may contain multiple
3714 // paragraphs. If I now take a look at the following code I get the impression that
3715 // our outliner is too complicate to be used properly,
3716 void SvxMSDffManager::ReadObjText( const OUString& rText, SdrObject* pObj )
3718 SdrTextObj* pText = DynCastSdrTextObj( pObj );
3719 if ( !pText )
3720 return;
3722 SdrOutliner& rOutliner = pText->ImpGetDrawOutliner();
3723 rOutliner.Init( OutlinerMode::TextObject );
3725 bool bOldUpdateMode = rOutliner.SetUpdateLayout( false );
3726 rOutliner.SetVertical( pText->IsVerticalWriting() );
3728 sal_Int32 nParaIndex = 0;
3729 sal_Int32 nParaSize;
3730 const sal_Unicode* pBuf = rText.getStr();
3731 const sal_Unicode* pEnd = rText.getStr() + rText.getLength();
3733 while( pBuf < pEnd )
3735 const sal_Unicode* pCurrent = pBuf;
3737 for ( nParaSize = 0; pBuf < pEnd; )
3739 sal_Unicode nChar = *pBuf++;
3740 if ( nChar == 0xa )
3742 if ( ( pBuf < pEnd ) && ( *pBuf == 0xd ) )
3743 pBuf++;
3744 break;
3746 else if ( nChar == 0xd )
3748 if ( ( pBuf < pEnd ) && ( *pBuf == 0xa ) )
3749 pBuf++;
3750 break;
3752 else
3753 ++nParaSize;
3755 ESelection aSelection( nParaIndex, 0, nParaIndex, 0 );
3756 OUString aParagraph( pCurrent, nParaSize );
3757 if ( !nParaIndex && aParagraph.isEmpty() ) // SJ: we are crashing if the first paragraph is empty ?
3758 aParagraph += " "; // otherwise these two lines can be removed.
3759 rOutliner.Insert( aParagraph, nParaIndex );
3760 rOutliner.SetParaAttribs( nParaIndex, rOutliner.GetEmptyItemSet() );
3762 SfxItemSet aParagraphAttribs( rOutliner.GetEmptyItemSet() );
3763 if ( !aSelection.nStartPos )
3764 aParagraphAttribs.Put( SfxBoolItem( EE_PARA_BULLETSTATE, false ) );
3765 aSelection.nStartPos = 0;
3766 rOutliner.QuickSetAttribs( aParagraphAttribs, aSelection );
3767 nParaIndex++;
3769 std::optional<OutlinerParaObject> pNewText = rOutliner.CreateParaObject();
3770 rOutliner.Clear();
3771 rOutliner.SetUpdateLayout( bOldUpdateMode );
3772 pText->SetOutlinerParaObject( std::move(pNewText) );
3773 // tdf#143315: restore stylesheet applied to Outliner's nodes when SdrTextObj initializes
3774 // its attributes, but removed by Outliner::Init, which calls Outliner::Clear.
3775 pText->SetStyleSheet(pText->GetStyleSheet(), true);
3778 //static
3779 OUString SvxMSDffManager::MSDFFReadZString(SvStream& rIn,
3780 sal_uInt32 nLen, bool bUniCode)
3782 if (!nLen)
3783 return OUString();
3785 OUString sBuf;
3787 if( bUniCode )
3788 sBuf = read_uInt16s_ToOUString(rIn, nLen/2);
3789 else
3790 sBuf = read_uInt8s_ToOUString(rIn, nLen, RTL_TEXTENCODING_MS_1252);
3792 return comphelper::string::stripEnd(sBuf, 0);
3795 static Size lcl_GetPrefSize(const Graphic& rGraf, const MapMode& aWanted)
3797 MapMode aPrefMapMode(rGraf.GetPrefMapMode());
3798 if (aPrefMapMode == aWanted)
3799 return rGraf.GetPrefSize();
3800 Size aRetSize;
3801 if (aPrefMapMode.GetMapUnit() == MapUnit::MapPixel)
3803 aRetSize = Application::GetDefaultDevice()->PixelToLogic(
3804 rGraf.GetPrefSize(), aWanted);
3806 else
3808 aRetSize = OutputDevice::LogicToLogic(
3809 rGraf.GetPrefSize(), rGraf.GetPrefMapMode(), aWanted);
3811 return aRetSize;
3814 // sj: if the parameter pSet is null, then the resulting crop bitmap will be stored in rGraf,
3815 // otherwise rGraf is untouched and pSet is used to store the corresponding SdrGrafCropItem
3816 static void lcl_ApplyCropping( const DffPropSet& rPropSet, SfxItemSet* pSet, Graphic& rGraf )
3818 sal_Int32 nCropTop = static_cast<sal_Int32>(rPropSet.GetPropertyValue( DFF_Prop_cropFromTop, 0 ));
3819 sal_Int32 nCropBottom = static_cast<sal_Int32>(rPropSet.GetPropertyValue( DFF_Prop_cropFromBottom, 0 ));
3820 sal_Int32 nCropLeft = static_cast<sal_Int32>(rPropSet.GetPropertyValue( DFF_Prop_cropFromLeft, 0 ));
3821 sal_Int32 nCropRight = static_cast<sal_Int32>(rPropSet.GetPropertyValue( DFF_Prop_cropFromRight, 0 ));
3823 if( !(nCropTop || nCropBottom || nCropLeft || nCropRight) )
3824 return;
3826 double fFactor;
3827 Size aCropSize;
3828 BitmapEx aCropBitmap;
3829 sal_uInt32 nTop( 0 ), nBottom( 0 ), nLeft( 0 ), nRight( 0 );
3831 // Cropping has to be applied on a loaded graphic.
3832 rGraf.makeAvailable();
3834 if ( pSet ) // use crop attributes ?
3835 aCropSize = lcl_GetPrefSize(rGraf, MapMode(MapUnit::Map100thMM));
3836 else
3838 aCropBitmap = rGraf.GetBitmapEx();
3839 aCropSize = aCropBitmap.GetSizePixel();
3841 if ( nCropTop )
3843 fFactor = static_cast<double>(nCropTop) / 65536.0;
3844 nTop = static_cast<sal_uInt32>( ( static_cast<double>( aCropSize.Height() + 1 ) * fFactor ) + 0.5 );
3846 if ( nCropBottom )
3848 fFactor = static_cast<double>(nCropBottom) / 65536.0;
3849 nBottom = static_cast<sal_uInt32>( ( static_cast<double>( aCropSize.Height() + 1 ) * fFactor ) + 0.5 );
3851 if ( nCropLeft )
3853 fFactor = static_cast<double>(nCropLeft) / 65536.0;
3854 nLeft = static_cast<sal_uInt32>( ( static_cast<double>( aCropSize.Width() + 1 ) * fFactor ) + 0.5 );
3856 if ( nCropRight )
3858 fFactor = static_cast<double>(nCropRight) / 65536.0;
3859 nRight = static_cast<sal_uInt32>( ( static_cast<double>( aCropSize.Width() + 1 ) * fFactor ) + 0.5 );
3861 if ( pSet ) // use crop attributes ?
3862 pSet->Put( SdrGrafCropItem( nLeft, nTop, nRight, nBottom ) );
3863 else
3865 tools::Rectangle aCropRect( nLeft, nTop, aCropSize.Width() - nRight, aCropSize.Height() - nBottom );
3866 aCropBitmap.Crop( aCropRect );
3867 rGraf = aCropBitmap;
3871 rtl::Reference<SdrObject> SvxMSDffManager::ImportGraphic( SvStream& rSt, SfxItemSet& rSet, const DffObjData& rObjData )
3873 rtl::Reference<SdrObject> pRet;
3874 OUString aLinkFileName;
3875 tools::Rectangle aVisArea;
3877 auto eFlags = GetPropertyValue(DFF_Prop_pibFlags, mso_blipflagDefault);
3878 sal_uInt32 nBlipId = GetPropertyValue( DFF_Prop_pib, 0 );
3879 bool bGrfRead = false,
3881 // Graphic linked
3882 bLinkGrf = 0 != ( eFlags & mso_blipflagLinkToFile );
3884 OUString aFileName;
3885 Graphic aGraf; // be sure this graphic is deleted before swapping out
3886 if( SeekToContent( DFF_Prop_pibName, rSt ) )
3887 aFileName = MSDFFReadZString( rSt, GetPropertyValue( DFF_Prop_pibName, 0 ), true );
3889 // AND, OR the following:
3890 if( !( eFlags & mso_blipflagDoNotSave ) ) // Graphic embedded
3892 bGrfRead = GetBLIP( nBlipId, aGraf, &aVisArea );
3893 if ( !bGrfRead )
3896 Still no luck, lets look at the end of this record for a FBSE pool,
3897 this fallback is a specific case for how word does it sometimes
3899 bool bOk = rObjData.rSpHd.SeekToEndOfRecord( rSt );
3900 DffRecordHeader aHd;
3901 if (bOk)
3903 bOk = ReadDffRecordHeader(rSt, aHd);
3905 if (bOk && DFF_msofbtBSE == aHd.nRecType)
3907 const sal_uInt8 nSkipBLIPLen = 20;
3908 const sal_uInt8 nSkipShapePos = 4;
3909 const sal_uInt8 nSkipBLIP = 4;
3910 const sal_uLong nSkip =
3911 nSkipBLIPLen + 4 + nSkipShapePos + 4 + nSkipBLIP;
3913 if (nSkip <= aHd.nRecLen)
3915 rSt.SeekRel(nSkip);
3916 if (ERRCODE_NONE == rSt.GetError())
3917 bGrfRead = GetBLIPDirect( rSt, aGraf, &aVisArea );
3922 if ( bGrfRead )
3924 // the writer is doing its own cropping, so this part affects only impress and calc,
3925 // unless we're inside a group, in which case writer doesn't crop either
3926 if (( GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_CROP_BITMAPS ) || rObjData.nCalledByGroup != 0 )
3927 lcl_ApplyCropping( *this, !bool( rObjData.nSpFlags & ShapeFlag::OLEShape ) ? &rSet : nullptr, aGraf );
3929 if ( IsProperty( DFF_Prop_pictureTransparent ) )
3931 sal_uInt32 nTransColor = GetPropertyValue( DFF_Prop_pictureTransparent, 0 );
3933 if ( aGraf.GetType() == GraphicType::Bitmap )
3935 BitmapEx aBitmapEx( aGraf.GetBitmapEx() );
3936 aBitmapEx.CombineMaskOr( MSO_CLR_ToColor( nTransColor, DFF_Prop_pictureTransparent ), 9 );
3937 aGraf = aBitmapEx;
3941 sal_Int32 nContrast = GetPropertyValue( DFF_Prop_pictureContrast, 0x10000 );
3943 0x10000 is msoffice 50%
3944 < 0x10000 is in units of 1/50th of 0x10000 per 1%
3945 > 0x10000 is in units where
3946 a msoffice x% is stored as 50/(100-x) * 0x10000
3948 plus, a (ui) microsoft % ranges from 0 to 100, OOO
3949 from -100 to 100, so also normalize into that range
3951 if ( nContrast > 0x10000 )
3953 double fX = nContrast;
3954 fX /= 0x10000;
3955 fX /= 51; // 50 + 1 to round
3956 fX = 1/fX;
3957 nContrast = static_cast<sal_Int32>(fX);
3958 nContrast -= 100;
3959 nContrast = -nContrast;
3960 nContrast = (nContrast-50)*2;
3962 else if ( nContrast == 0x10000 )
3963 nContrast = 0;
3964 else
3966 if (o3tl::checked_multiply<sal_Int32>(nContrast, 101, nContrast)) //100 + 1 to round
3968 SAL_WARN("filter.ms", "bad Contrast value:" << nContrast);
3969 nContrast = 0;
3971 else
3973 nContrast /= 0x10000;
3974 nContrast -= 100;
3977 sal_Int16 nBrightness = static_cast<sal_Int16>( static_cast<sal_Int32>(GetPropertyValue( DFF_Prop_pictureBrightness, 0 )) / 327 );
3978 sal_Int32 nGamma = GetPropertyValue( DFF_Prop_pictureGamma, 0x10000 );
3979 GraphicDrawMode eDrawMode = GraphicDrawMode::Standard;
3980 switch ( GetPropertyValue( DFF_Prop_pictureActive, 0 ) & 6 )
3982 case 4 : eDrawMode = GraphicDrawMode::Greys; break;
3983 case 6 : eDrawMode = GraphicDrawMode::Mono; break;
3984 case 0 :
3986 //office considers the converted values of (in OOo) 70 to be the
3987 //"watermark" values, which can vary slightly due to rounding from the
3988 //above values
3989 if (( nContrast == -70 ) && ( nBrightness == 70 ))
3991 nContrast = 0;
3992 nBrightness = 0;
3993 eDrawMode = GraphicDrawMode::Watermark;
3996 break;
3999 if ( nContrast || nBrightness || ( nGamma != 0x10000 ) || ( eDrawMode != GraphicDrawMode::Standard ) )
4001 // MSO uses a different algorithm for contrast+brightness, LO applies contrast before brightness,
4002 // while MSO apparently applies half of brightness before contrast and half after. So if only
4003 // contrast or brightness need to be altered, the result is the same, but if both are involved,
4004 // there's no way to map that, so just force a conversion of the image.
4005 bool needsConversion = nContrast != 0 && nBrightness != 0;
4006 if ( !bool(rObjData.nSpFlags & ShapeFlag::OLEShape) && !needsConversion )
4008 if ( nBrightness )
4009 rSet.Put( SdrGrafLuminanceItem( nBrightness ) );
4010 if ( nContrast )
4011 rSet.Put( SdrGrafContrastItem( static_cast<sal_Int16>(nContrast) ) );
4012 if ( nGamma != 0x10000 )
4013 rSet.Put( SdrGrafGamma100Item( nGamma / 655 ) );
4014 if ( eDrawMode != GraphicDrawMode::Standard )
4015 rSet.Put( SdrGrafModeItem( eDrawMode ) );
4017 else
4019 if ( eDrawMode == GraphicDrawMode::Watermark )
4021 nContrast = 60;
4022 nBrightness = 70;
4023 eDrawMode = GraphicDrawMode::Standard;
4025 switch ( aGraf.GetType() )
4027 case GraphicType::Bitmap :
4029 BitmapEx aBitmapEx( aGraf.GetBitmapEx() );
4030 if ( nBrightness || nContrast || ( nGamma != 0x10000 ) )
4031 aBitmapEx.Adjust( nBrightness, static_cast<sal_Int16>(nContrast), 0, 0, 0, static_cast<double>(nGamma) / 0x10000, false, true );
4032 if ( eDrawMode == GraphicDrawMode::Greys )
4033 aBitmapEx.Convert( BmpConversion::N8BitGreys );
4034 else if ( eDrawMode == GraphicDrawMode::Mono )
4035 aBitmapEx.Convert( BmpConversion::N1BitThreshold );
4036 aGraf = aBitmapEx;
4039 break;
4041 case GraphicType::GdiMetafile :
4043 GDIMetaFile aGdiMetaFile( aGraf.GetGDIMetaFile() );
4044 if ( nBrightness || nContrast || ( nGamma != 0x10000 ) )
4045 aGdiMetaFile.Adjust( nBrightness, static_cast<sal_Int16>(nContrast), 0, 0, 0, static_cast<double>(nGamma) / 0x10000, false, true );
4046 if ( eDrawMode == GraphicDrawMode::Greys )
4047 aGdiMetaFile.Convert( MtfConversion::N8BitGreys );
4048 else if ( eDrawMode == GraphicDrawMode::Mono )
4049 aGdiMetaFile.Convert( MtfConversion::N1BitThreshold );
4050 aGraf = aGdiMetaFile;
4052 break;
4053 default: break;
4059 // should it be an OLE object?
4060 if( bGrfRead && !bLinkGrf && IsProperty( DFF_Prop_pictureId ) )
4062 // TODO/LATER: in future probably the correct aspect should be provided here
4063 // #i32596# - pass <nCalledByGroup> to method
4064 pRet = ImportOLE( GetPropertyValue( DFF_Prop_pictureId, 0 ), aGraf, rObjData.aBoundRect, aVisArea, rObjData.nCalledByGroup );
4066 if( !pRet )
4068 pRet = new SdrGrafObj(*pSdrModel);
4069 if( bGrfRead )
4070 static_cast<SdrGrafObj*>(pRet.get())->SetGraphic( aGraf );
4072 if( bLinkGrf && !bGrfRead ) // sj: #i55484# if the graphic was embedded ( bGrfRead == true ) then
4073 { // we do not need to set a link. TODO: not to lose the information where the graphic is linked from
4074 INetURLObject aAbsURL;
4075 if ( !INetURLObject( maBaseURL ).GetNewAbsURL( aFileName, &aAbsURL ) )
4077 OUString aValidURL;
4078 if( osl::FileBase::getFileURLFromSystemPath( aFileName, aValidURL ) == osl::FileBase::E_None )
4079 aAbsURL = INetURLObject( aValidURL );
4081 if( aAbsURL.GetProtocol() != INetProtocol::NotValid )
4083 aLinkFileName = aAbsURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri );
4085 else
4086 aLinkFileName = aFileName;
4090 // set the size from BLIP if there is one
4091 if ( bGrfRead && !aVisArea.IsEmpty() )
4092 pRet->SetBLIPSizeRectangle( aVisArea );
4094 if (pRet->GetName().isEmpty()) // SJ 22.02.00 : PPT OLE IMPORT:
4095 { // name is already set in ImportOLE !!
4096 // JP 01.12.99: SetName before SetModel - because in the other order the Bug 70098 is active
4097 if ( ( eFlags & mso_blipflagType ) != mso_blipflagComment )
4099 INetURLObject aURL;
4100 aURL.SetSmartURL( aFileName );
4101 pRet->SetName( aURL.getBase() );
4103 else
4104 pRet->SetName( aFileName );
4107 pRet->NbcSetLogicRect( rObjData.aBoundRect );
4109 if (SdrGrafObj* pGrafObj = dynamic_cast<SdrGrafObj*>(pRet.get()))
4111 if( aLinkFileName.getLength() )
4113 pGrafObj->SetGraphicLink( aLinkFileName );
4114 Graphic aGraphic(pGrafObj->GetGraphic());
4115 aGraphic.setOriginURL(aLinkFileName);
4118 if ( bLinkGrf && !bGrfRead )
4120 Graphic aGraf(pGrafObj->GetGraphic());
4121 lcl_ApplyCropping( *this, &rSet, aGraf );
4125 return pRet;
4128 // PptSlidePersistEntry& rPersistEntry, SdPage* pPage
4129 rtl::Reference<SdrObject> SvxMSDffManager::ImportObj( SvStream& rSt, SvxMSDffClientData& rClientData,
4130 tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect, int nCalledByGroup, sal_Int32* pShapeId )
4132 rtl::Reference<SdrObject> pRet;
4133 DffRecordHeader aObjHd;
4134 bool bOk = ReadDffRecordHeader(rSt, aObjHd);
4135 if (bOk && aObjHd.nRecType == DFF_msofbtSpgrContainer)
4137 pRet = ImportGroup( aObjHd, rSt, rClientData, rClientRect, rGlobalChildRect, nCalledByGroup, pShapeId );
4139 else if (bOk && aObjHd.nRecType == DFF_msofbtSpContainer)
4141 pRet = ImportShape( aObjHd, rSt, rClientData, rClientRect, rGlobalChildRect, nCalledByGroup, pShapeId );
4143 aObjHd.SeekToBegOfRecord( rSt ); // restore FilePos
4144 return pRet;
4147 rtl::Reference<SdrObject> SvxMSDffManager::ImportGroup( const DffRecordHeader& rHd, SvStream& rSt, SvxMSDffClientData& rClientData,
4148 tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect,
4149 int nCalledByGroup, sal_Int32* pShapeId )
4151 if( pShapeId )
4152 *pShapeId = 0;
4154 if (!rHd.SeekToContent(rSt))
4155 return nullptr;
4157 rtl::Reference<SdrObject> xRet;
4159 DffRecordHeader aRecHd; // the first atom has to be the SpContainer for the GroupObject
4160 bool bOk = ReadDffRecordHeader(rSt, aRecHd);
4161 if (bOk && aRecHd.nRecType == DFF_msofbtSpContainer)
4163 mnFix16Angle = 0_deg100;
4164 if (!aRecHd.SeekToBegOfRecord(rSt))
4165 return xRet;
4166 xRet = ImportObj(rSt, rClientData, rClientRect, rGlobalChildRect, nCalledByGroup + 1, pShapeId);
4167 if (xRet)
4169 Degree100 nGroupRotateAngle(0);
4170 ShapeFlag nSpFlags = nGroupShapeFlags;
4171 nGroupRotateAngle = mnFix16Angle;
4173 tools::Rectangle aClientRect( rClientRect );
4175 tools::Rectangle aGlobalChildRect;
4176 if ( !nCalledByGroup || rGlobalChildRect.IsEmpty() )
4177 aGlobalChildRect = GetGlobalChildAnchor( rHd, rSt, aClientRect );
4178 else
4179 aGlobalChildRect = rGlobalChildRect;
4181 if ( ( nGroupRotateAngle > 4500_deg100 && nGroupRotateAngle <= 13500_deg100 )
4182 || ( nGroupRotateAngle > 22500_deg100 && nGroupRotateAngle <= 31500_deg100 ) )
4184 sal_Int32 nHalfWidth = ( aClientRect.GetWidth() + 1 ) >> 1;
4185 sal_Int32 nHalfHeight = ( aClientRect.GetHeight() + 1 ) >> 1;
4186 Point aTopLeft( aClientRect.Left() + nHalfWidth - nHalfHeight,
4187 aClientRect.Top() + nHalfHeight - nHalfWidth );
4188 const tools::Long nRotatedWidth = aClientRect.GetHeight();
4189 const tools::Long nRotatedHeight = aClientRect.GetWidth();
4190 Size aNewSize(nRotatedWidth, nRotatedHeight);
4191 tools::Rectangle aNewRect( aTopLeft, aNewSize );
4192 aClientRect = aNewRect;
4195 // now importing the inner objects of the group
4196 if (!aRecHd.SeekToEndOfRecord(rSt))
4197 return xRet;
4199 while (rSt.good() && ( rSt.Tell() < rHd.GetRecEndFilePos()))
4201 DffRecordHeader aRecHd2;
4202 if (!ReadDffRecordHeader(rSt, aRecHd2))
4203 break;
4204 if ( aRecHd2.nRecType == DFF_msofbtSpgrContainer )
4206 tools::Rectangle aGroupClientAnchor, aGroupChildAnchor;
4207 GetGroupAnchors( aRecHd2, rSt, aGroupClientAnchor, aGroupChildAnchor, aClientRect, aGlobalChildRect );
4208 if (!aRecHd2.SeekToBegOfRecord(rSt))
4209 return xRet;
4210 sal_Int32 nShapeId;
4211 rtl::Reference<SdrObject> pTmp = ImportGroup( aRecHd2, rSt, rClientData, aGroupClientAnchor, aGroupChildAnchor, nCalledByGroup + 1, &nShapeId );
4212 if (pTmp)
4214 SdrObjGroup* pGroup = dynamic_cast<SdrObjGroup*>(xRet.get());
4215 if (pGroup && pGroup->GetSubList())
4217 pGroup->GetSubList()->NbcInsertObject(pTmp.get());
4218 if (nShapeId)
4219 insertShapeId(nShapeId, pTmp.get());
4221 else
4222 FreeObj(rClientData, pTmp.get());
4225 else if ( aRecHd2.nRecType == DFF_msofbtSpContainer )
4227 if (!aRecHd2.SeekToBegOfRecord(rSt))
4228 return xRet;
4229 sal_Int32 nShapeId;
4230 rtl::Reference<SdrObject> pTmp = ImportShape( aRecHd2, rSt, rClientData, aClientRect, aGlobalChildRect, nCalledByGroup + 1, &nShapeId );
4231 if (pTmp)
4233 SdrObjGroup* pGroup = dynamic_cast<SdrObjGroup*>(xRet.get());
4234 if (pGroup && pGroup->GetSubList())
4236 pGroup->GetSubList()->NbcInsertObject(pTmp.get());
4237 if (nShapeId)
4238 insertShapeId(nShapeId, pTmp.get());
4240 else
4241 FreeObj(rClientData, pTmp.get());
4244 if (!aRecHd2.SeekToEndOfRecord(rSt))
4245 return xRet;
4248 if ( nGroupRotateAngle )
4249 xRet->NbcRotate( aClientRect.Center(), nGroupRotateAngle );
4250 if ( nSpFlags & ShapeFlag::FlipV )
4251 { // BoundRect in aBoundRect
4252 Point aLeft( aClientRect.Left(), ( aClientRect.Top() + aClientRect.Bottom() ) >> 1 );
4253 Point aRight( aLeft.X() + 1000, aLeft.Y() );
4254 xRet->NbcMirror( aLeft, aRight );
4256 if ( nSpFlags & ShapeFlag::FlipH )
4257 { // BoundRect in aBoundRect
4258 Point aTop( ( aClientRect.Left() + aClientRect.Right() ) >> 1, aClientRect.Top() );
4259 Point aBottom( aTop.X(), aTop.Y() + 1000 );
4260 xRet->NbcMirror( aTop, aBottom );
4264 if (o3tl::make_unsigned(nCalledByGroup) < maPendingGroupData.size())
4266 // finalization for this group is pending, do it now
4267 xRet = FinalizeObj(maPendingGroupData.back().first, xRet.get());
4268 maPendingGroupData.pop_back();
4270 return xRet;
4273 rtl::Reference<SdrObject> SvxMSDffManager::ImportShape( const DffRecordHeader& rHd, SvStream& rSt, SvxMSDffClientData& rClientData,
4274 tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect,
4275 int nCalledByGroup, sal_Int32* pShapeId )
4277 if( pShapeId )
4278 *pShapeId = 0;
4280 if (!rHd.SeekToBegOfRecord(rSt))
4281 return nullptr;
4283 DffObjData aObjData( rHd, rClientRect, nCalledByGroup );
4285 aObjData.bRotateTextWithShape = ( GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_EXCEL ) == 0;
4286 maShapeRecords.Consume( rSt );
4287 if( maShapeRecords.SeekToContent( rSt,
4288 DFF_msofbtUDefProp ) )
4290 sal_uInt32 nBytesLeft = maShapeRecords.Current()->nRecLen;
4291 while( 5 < nBytesLeft )
4293 sal_uInt16 nPID(0);
4294 rSt.ReadUInt16(nPID);
4295 if (!rSt.good())
4296 break;
4297 sal_uInt32 nUDData(0);
4298 rSt.ReadUInt32(nUDData);
4299 if (!rSt.good())
4300 break;
4301 if (nPID == 447)
4303 mbRotateGranientFillWithAngle = nUDData & 0x20;
4304 break;
4306 nBytesLeft -= 6;
4309 aObjData.bShapeType = maShapeRecords.SeekToContent( rSt, DFF_msofbtSp );
4310 if ( aObjData.bShapeType )
4312 sal_uInt32 temp(0);
4313 rSt.ReadUInt32( aObjData.nShapeId )
4314 .ReadUInt32( temp );
4315 aObjData.nSpFlags = ShapeFlag(temp);
4316 aObjData.eShapeType = static_cast<MSO_SPT>(maShapeRecords.Current()->nRecInstance);
4318 else
4320 aObjData.nShapeId = 0;
4321 aObjData.nSpFlags = ShapeFlag::NONE;
4322 aObjData.eShapeType = mso_sptNil;
4325 if( pShapeId )
4326 *pShapeId = aObjData.nShapeId;
4328 aObjData.bOpt = maShapeRecords.SeekToContent( rSt, DFF_msofbtOPT, SEEK_FROM_CURRENT_AND_RESTART );
4329 if ( aObjData.bOpt )
4331 if (!maShapeRecords.Current()->SeekToBegOfRecord(rSt))
4332 return nullptr;
4333 #ifdef DBG_AUTOSHAPE
4334 ReadPropSet( rSt, &rClientData, (sal_uInt32)aObjData.eShapeType );
4335 #else
4336 ReadPropSet( rSt, &rClientData );
4337 #endif
4339 else
4341 InitializePropSet( DFF_msofbtOPT ); // get the default PropSet
4342 static_cast<DffPropertyReader*>(this)->mnFix16Angle = 0_deg100;
4345 aObjData.bOpt2 = maShapeRecords.SeekToContent( rSt, DFF_msofbtUDefProp, SEEK_FROM_CURRENT_AND_RESTART );
4346 if ( aObjData.bOpt2 )
4348 maShapeRecords.Current()->SeekToBegOfRecord( rSt );
4349 pSecPropSet.reset( new DffPropertyReader( *this ) );
4350 pSecPropSet->ReadPropSet( rSt, nullptr );
4353 aObjData.bChildAnchor = maShapeRecords.SeekToContent( rSt, DFF_msofbtChildAnchor, SEEK_FROM_CURRENT_AND_RESTART );
4354 if ( aObjData.bChildAnchor )
4356 sal_Int32 l(0), o(0), r(0), u(0);
4357 rSt.ReadInt32( l ).ReadInt32( o ).ReadInt32( r ).ReadInt32( u );
4358 Scale( l );
4359 Scale( o );
4360 Scale( r );
4361 Scale( u );
4362 aObjData.aChildAnchor = tools::Rectangle( l, o, r, u );
4363 sal_Int32 nWidth, nHeight;
4364 if (!rGlobalChildRect.IsEmpty() && !rClientRect.IsEmpty() && rGlobalChildRect.GetWidth() && rGlobalChildRect.GetHeight() &&
4365 !o3tl::checked_sub(r, l, nWidth) && !o3tl::checked_sub(u, o, nHeight))
4367 double fXScale = static_cast<double>(rClientRect.GetWidth()) / static_cast<double>(rGlobalChildRect.GetWidth());
4368 double fYScale = static_cast<double>(rClientRect.GetHeight()) / static_cast<double>(rGlobalChildRect.GetHeight());
4369 double fl = ( ( l - rGlobalChildRect.Left() ) * fXScale ) + rClientRect.Left();
4370 double fo = ( ( o - rGlobalChildRect.Top() ) * fYScale ) + rClientRect.Top();
4371 double fWidth = nWidth * fXScale;
4372 double fHeight = nHeight * fYScale;
4373 aObjData.aChildAnchor = tools::Rectangle( Point( fl, fo ), Size( fWidth + 1, fHeight + 1 ) );
4377 aObjData.bClientAnchor = maShapeRecords.SeekToContent( rSt, DFF_msofbtClientAnchor, SEEK_FROM_CURRENT_AND_RESTART );
4378 if ( aObjData.bClientAnchor )
4379 ProcessClientAnchor2( rSt, *maShapeRecords.Current(), aObjData );
4381 if ( aObjData.bChildAnchor )
4382 aObjData.aBoundRect = aObjData.aChildAnchor;
4384 if ( aObjData.nSpFlags & ShapeFlag::Background )
4385 aObjData.aBoundRect = tools::Rectangle( Point(), Size( 1, 1 ) );
4387 rtl::Reference<SdrObject> xRet;
4389 tools::Rectangle aTextRect;
4390 if ( !aObjData.aBoundRect.IsEmpty() )
4391 { // apply rotation to the BoundingBox BEFORE an object has been generated
4392 if( mnFix16Angle )
4394 Degree100 nAngle = mnFix16Angle;
4395 if ( ( nAngle > 4500_deg100 && nAngle <= 13500_deg100 ) || ( nAngle > 22500_deg100 && nAngle <= 31500_deg100 ) )
4397 sal_Int32 nHalfWidth = ( aObjData.aBoundRect.GetWidth() + 1 ) >> 1;
4398 sal_Int32 nHalfHeight = ( aObjData.aBoundRect.GetHeight() + 1 ) >> 1;
4399 Point aTopLeft( aObjData.aBoundRect.Left() + nHalfWidth - nHalfHeight,
4400 aObjData.aBoundRect.Top() + nHalfHeight - nHalfWidth );
4401 Size aNewSize( aObjData.aBoundRect.GetHeight(), aObjData.aBoundRect.GetWidth() );
4402 tools::Rectangle aNewRect( aTopLeft, aNewSize );
4403 aObjData.aBoundRect = aNewRect;
4406 aTextRect = aObjData.aBoundRect;
4407 bool bGraphic = IsProperty( DFF_Prop_pib ) ||
4408 IsProperty( DFF_Prop_pibName ) ||
4409 IsProperty( DFF_Prop_pibFlags );
4411 if ( aObjData.nSpFlags & ShapeFlag::Group )
4413 xRet = new SdrObjGroup(*pSdrModel);
4414 /* After CWS aw033 has been integrated, an empty group object
4415 cannot store its resulting bounding rectangle anymore. We have
4416 to return this rectangle via rClientRect now, but only, if
4417 caller has not passed an own bounding ractangle. */
4418 if ( rClientRect.IsEmpty() )
4419 rClientRect = aObjData.aBoundRect;
4420 nGroupShapeFlags = aObjData.nSpFlags;
4422 else if ( ( aObjData.eShapeType != mso_sptNil ) || IsProperty( DFF_Prop_pVertices ) || bGraphic )
4424 SfxItemSet aSet( pSdrModel->GetItemPool() );
4426 bool bIsConnector = ( ( aObjData.eShapeType >= mso_sptStraightConnector1 ) && ( aObjData.eShapeType <= mso_sptCurvedConnector5 ) );
4427 Degree100 nObjectRotation = mnFix16Angle;
4428 ShapeFlag nSpFlags = aObjData.nSpFlags;
4430 if ( bGraphic )
4432 if (!mbSkipImages) {
4433 xRet = ImportGraphic(rSt, aSet, aObjData); // SJ: #68396# is no longer true (fixed in ppt2000)
4434 ApplyAttributes( rSt, aSet, aObjData );
4435 xRet->SetMergedItemSet(aSet);
4438 else if ( aObjData.eShapeType == mso_sptLine && !( GetPropertyValue( DFF_Prop_fc3DLightFace, 0 ) & 8 ) )
4440 basegfx::B2DPolygon aPoly;
4441 aPoly.append(basegfx::B2DPoint(aObjData.aBoundRect.Left(), aObjData.aBoundRect.Top()));
4442 aPoly.append(basegfx::B2DPoint(aObjData.aBoundRect.Right(), aObjData.aBoundRect.Bottom()));
4443 xRet = new SdrPathObj(
4444 *pSdrModel,
4445 SdrObjKind::Line,
4446 basegfx::B2DPolyPolygon(aPoly));
4447 ApplyAttributes( rSt, aSet, aObjData );
4448 xRet->SetMergedItemSet(aSet);
4450 else
4452 if ( GetCustomShapeContent( aObjData.eShapeType ) || IsProperty( DFF_Prop_pVertices ) )
4455 ApplyAttributes( rSt, aSet, aObjData );
4457 xRet = new SdrObjCustomShape(*pSdrModel);
4459 sal_uInt32 ngtextFStrikethrough = GetPropertyValue( DFF_Prop_gtextFStrikethrough, 0 );
4460 bool bIsFontwork = ( ngtextFStrikethrough & 0x4000 ) != 0;
4462 // in case of a FontWork, the text is set by the escher import
4463 if ( bIsFontwork )
4465 OUString aObjectText;
4466 OUString aFontName;
4468 if ( SeekToContent( DFF_Prop_gtextFont, rSt ) )
4470 SvxFontItem aLatin(EE_CHAR_FONTINFO), aAsian(EE_CHAR_FONTINFO_CJK), aComplex(EE_CHAR_FONTINFO_CTL);
4471 GetDefaultFonts( aLatin, aAsian, aComplex );
4473 aFontName = MSDFFReadZString( rSt, GetPropertyValue( DFF_Prop_gtextFont, 0 ), true );
4474 aSet.Put( SvxFontItem( aLatin.GetFamily(), aFontName, aLatin.GetStyleName(),
4475 PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, EE_CHAR_FONTINFO ));
4476 aSet.Put( SvxFontItem( aLatin.GetFamily(), aFontName, aLatin.GetStyleName(),
4477 PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, EE_CHAR_FONTINFO_CJK ) );
4478 aSet.Put( SvxFontItem( aLatin.GetFamily(), aFontName, aLatin.GetStyleName(),
4479 PITCH_DONTKNOW, RTL_TEXTENCODING_DONTKNOW, EE_CHAR_FONTINFO_CTL ) );
4482 // SJ: applying fontattributes for Fontwork :
4483 if ( IsHardAttribute( DFF_Prop_gtextFItalic ) )
4484 aSet.Put( SvxPostureItem( ( ngtextFStrikethrough & 0x0010 ) != 0 ? ITALIC_NORMAL : ITALIC_NONE, EE_CHAR_ITALIC ) );
4486 if ( IsHardAttribute( DFF_Prop_gtextFBold ) )
4487 aSet.Put( SvxWeightItem( ( ngtextFStrikethrough & 0x0020 ) != 0 ? WEIGHT_BOLD : WEIGHT_NORMAL, EE_CHAR_WEIGHT ) );
4489 // SJ TODO: Vertical Writing is not correct, instead
4490 // this should be replaced through "CharacterRotation"
4491 // by 90 degrees, therefore a new Item has to be
4492 // supported by svx core, api and xml file format
4493 static_cast<SdrObjCustomShape*>(xRet.get())->SetVerticalWriting( ( ngtextFStrikethrough & 0x2000 ) != 0 );
4495 if ( SeekToContent( DFF_Prop_gtextUNICODE, rSt ) )
4497 aObjectText = MSDFFReadZString( rSt, GetPropertyValue( DFF_Prop_gtextUNICODE, 0 ), true );
4498 ReadObjText(aObjectText, xRet.get());
4501 auto eGeoTextAlign = GetPropertyValue(DFF_Prop_gtextAlign, mso_alignTextCenter);
4503 SdrTextHorzAdjust eHorzAdjust;
4504 switch( eGeoTextAlign )
4506 case mso_alignTextLetterJust :
4507 case mso_alignTextWordJust :
4508 case mso_alignTextStretch : eHorzAdjust = SDRTEXTHORZADJUST_BLOCK; break;
4509 default:
4510 case mso_alignTextInvalid :
4511 case mso_alignTextCenter : eHorzAdjust = SDRTEXTHORZADJUST_CENTER; break;
4512 case mso_alignTextLeft : eHorzAdjust = SDRTEXTHORZADJUST_LEFT; break;
4513 case mso_alignTextRight : eHorzAdjust = SDRTEXTHORZADJUST_RIGHT; break;
4515 aSet.Put( SdrTextHorzAdjustItem( eHorzAdjust ) );
4517 drawing::TextFitToSizeType eFTS = drawing::TextFitToSizeType_NONE;
4518 if ( eGeoTextAlign == mso_alignTextStretch )
4519 eFTS = drawing::TextFitToSizeType_ALLLINES;
4520 aSet.Put( SdrTextFitToSizeTypeItem( eFTS ) );
4522 if ( IsProperty( DFF_Prop_gtextSpacing ) )
4524 sal_Int32 nTextWidth = GetPropertyValue( DFF_Prop_gtextSpacing, 1 << 16 ) / 655;
4525 if ( nTextWidth != 100 )
4526 aSet.Put( SvxCharScaleWidthItem( static_cast<sal_uInt16>(nTextWidth), EE_CHAR_FONTWIDTH ) );
4528 if ( ngtextFStrikethrough & 0x1000 ) // SJ: Font Kerning On ?
4529 aSet.Put( SvxKerningItem( 1, EE_CHAR_KERNING ) );
4531 // #i119496# the resize autoshape to fit text attr of word art in MS PPT is always false
4532 aSet.Put(makeSdrTextAutoGrowHeightItem(false));
4533 aSet.Put(makeSdrTextAutoGrowWidthItem(false));
4535 bool bWithPadding = !( ngtextFStrikethrough & use_gtextFBestFit
4536 && ngtextFStrikethrough & use_gtextFShrinkFit
4537 && ngtextFStrikethrough & use_gtextFStretch
4538 && ngtextFStrikethrough & gtextFBestFit
4539 && ngtextFStrikethrough & gtextFShrinkFit
4540 && ngtextFStrikethrough & gtextFStretch );
4542 if ( bWithPadding )
4544 // trim, remove additional space
4545 VclPtr<VirtualDevice> pDevice = VclPtr<VirtualDevice>::Create();
4546 vcl::Font aFont = pDevice->GetFont();
4547 aFont.SetFamilyName( aFontName );
4548 aFont.SetFontSize( Size( 0, 96 ) );
4549 pDevice->SetFont( aFont );
4551 auto nTextWidth = pDevice->GetTextWidth( aObjectText );
4552 OUString aObjName = GetPropertyString( DFF_Prop_wzName, rSt );
4553 if ( nTextWidth && aObjData.eShapeType == mso_sptTextPlainText
4554 && aObjName.match( "PowerPlusWaterMarkObject" ) )
4556 double fRatio = static_cast<double>(pDevice->GetTextHeight()) / nTextWidth;
4557 sal_Int32 nNewHeight = fRatio * aObjData.aBoundRect.getOpenWidth();
4558 sal_Int32 nPaddingY = aObjData.aBoundRect.getOpenHeight() - nNewHeight;
4560 if ( nPaddingY > 0 )
4561 aObjData.aBoundRect.setHeight( nNewHeight );
4565 xRet->SetMergedItemSet( aSet );
4567 // sj: taking care of rtl, ltr. In case of fontwork mso. seems not to be able to set
4568 // proper text directions, instead the text default is depending to the string.
4569 // so we have to calculate the a text direction from string:
4570 if ( bIsFontwork )
4572 OutlinerParaObject* pParaObj = static_cast<SdrObjCustomShape*>(xRet.get())->GetOutlinerParaObject();
4573 if ( pParaObj )
4575 SdrOutliner& rOutliner = static_cast<SdrObjCustomShape*>(xRet.get())->ImpGetDrawOutliner();
4576 rOutliner.SetStyleSheetPool(static_cast< SfxStyleSheetPool* >(xRet->getSdrModelFromSdrObject().GetStyleSheetPool()));
4577 bool bOldUpdateMode = rOutliner.SetUpdateLayout( false );
4578 rOutliner.SetText( *pParaObj );
4579 ScopedVclPtrInstance< VirtualDevice > pVirDev(DeviceFormat::WITHOUT_ALPHA);
4580 pVirDev->SetMapMode(MapMode(MapUnit::Map100thMM));
4581 sal_Int32 i, nParagraphs = rOutliner.GetParagraphCount();
4582 if ( nParagraphs )
4584 bool bCreateNewParaObject = false;
4585 for ( i = 0; i < nParagraphs; i++ )
4587 OUString aString(rOutliner.GetText(rOutliner.GetParagraph(i)));
4588 bool bIsRTL = pVirDev->GetTextIsRTL(aString, 0, aString.getLength());
4589 if ( bIsRTL )
4591 SfxItemSet aSet2( rOutliner.GetParaAttribs( i ) );
4592 aSet2.Put( SvxFrameDirectionItem( SvxFrameDirection::Horizontal_RL_TB, EE_PARA_WRITINGDIR ) );
4593 rOutliner.SetParaAttribs( i, aSet2 );
4594 bCreateNewParaObject = true;
4597 if ( bCreateNewParaObject )
4599 std::optional<OutlinerParaObject> pNewText = rOutliner.CreateParaObject();
4600 rOutliner.Init( OutlinerMode::TextObject );
4601 static_cast<SdrObjCustomShape*>(xRet.get())->NbcSetOutlinerParaObject( std::move(pNewText) );
4604 rOutliner.Clear();
4605 rOutliner.SetUpdateLayout( bOldUpdateMode );
4609 // mso_sptArc special treating
4610 // tdf#124029: A new custom shape is generated from prototype 'msoArc'. Values, which are
4611 // read here, are adapted and merged. The shape type is changed, so this code
4612 // applies only if importing arcs from MS Office.
4613 if ( aObjData.eShapeType == mso_sptArc )
4615 static const OUStringLiteral sAdjustmentValues( u"AdjustmentValues" );
4616 static const OUStringLiteral sViewBox( u"ViewBox" );
4617 static const OUStringLiteral sPath( u"Path" );
4618 SdrCustomShapeGeometryItem aGeometryItem( static_cast<SdrObjCustomShape*>(xRet.get())->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
4619 PropertyValue aPropVal;
4621 // The default arc goes form -90deg to 0deg. Replace general defaults used
4622 // when read from stream with this specific values.
4623 double fStartAngle(-90.0);
4624 double fEndAngle(0.0);
4625 css::uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > seqAdjustmentValues;
4626 const uno::Any* pAny = aGeometryItem.GetPropertyValueByName(sAdjustmentValues);
4627 if (pAny && (*pAny >>= seqAdjustmentValues) && seqAdjustmentValues.getLength() > 1)
4629 auto pseqAdjustmentValues = seqAdjustmentValues.getArray();
4630 if (seqAdjustmentValues[0].State == css::beans::PropertyState_DEFAULT_VALUE)
4632 pseqAdjustmentValues[0].Value <<= -90.0;
4633 pseqAdjustmentValues[0].State = com::sun::star::beans::PropertyState_DIRECT_VALUE;
4635 if (seqAdjustmentValues[1].State == css::beans::PropertyState_DEFAULT_VALUE)
4637 pseqAdjustmentValues[1].Value <<= 0.0;
4638 pseqAdjustmentValues[1].State = com::sun::star::beans::PropertyState_DIRECT_VALUE;
4640 seqAdjustmentValues[0].Value >>= fStartAngle;
4641 seqAdjustmentValues[1].Value >>= fEndAngle;
4642 aPropVal.Name = sAdjustmentValues;
4643 aPropVal.Value <<= seqAdjustmentValues;
4644 aGeometryItem.SetPropertyValue(aPropVal);
4647 // arc first command is always wr -- clockwise arc
4648 // the parameters are : (left,top),(right,bottom),start(x,y),end(x,y)
4649 // The left/top vertex of the frame rectangle of the sector is the origin
4650 // of the shape internal coordinate system in MS Office. The default arc
4651 // has an ellipse frame rectangle with LT(-21600,0) and
4652 // RB(21600,43200) in this coordinate system.
4653 basegfx::B2DRectangle aEllipseRect_MS(-21600.0, 0.0, 21600.0, 43200.0);
4654 css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> seqCoordinates;
4655 pAny = aGeometryItem.GetPropertyValueByName( sPath, "Coordinates" );
4656 if (pAny && (*pAny >>= seqCoordinates) && (seqCoordinates.getLength() >= 2))
4658 auto const nL
4659 = *o3tl::doAccess<sal_Int32>(seqCoordinates[0].First.Value);
4660 auto const nT
4661 = *o3tl::doAccess<sal_Int32>(seqCoordinates[0].Second.Value);
4662 auto const nR
4663 = *o3tl::doAccess<sal_Int32>(seqCoordinates[1].First.Value);
4664 auto const nB
4665 = *o3tl::doAccess<sal_Int32>(seqCoordinates[1].Second.Value);
4666 aEllipseRect_MS = basegfx::B2DRectangle(nL, nT, nR, nB);
4669 // MS Office uses the pie frame rectangle as reference for outer position
4670 // and size of the shape and for text in the shape. We can get this rectangle
4671 // from imported viewBox or from the arc geometry.
4672 basegfx::B2DRectangle aPieRect_MS(0.0 , 0.0, 21600.0, 21600.0);
4673 pAny = aGeometryItem.GetPropertyValueByName(sPath,sViewBox);
4674 css::awt::Rectangle aImportedViewBox;
4675 if (pAny && (*pAny >>= aImportedViewBox))
4677 aPieRect_MS = basegfx::B2DRectangle( aImportedViewBox.X,
4678 aImportedViewBox.Y,
4679 aImportedViewBox.X + aImportedViewBox.Width,
4680 aImportedViewBox.Y + aImportedViewBox.Height);
4682 else
4684 double fRadStartAngle(basegfx::deg2rad(NormAngle360(fStartAngle)));
4685 double fRadEndAngle(basegfx::deg2rad(NormAngle360(fEndAngle)));
4686 basegfx::B2DPoint aCenter(aEllipseRect_MS.getCenter());
4687 basegfx::B2DPolygon aTempPie(
4688 basegfx::utils::createPolygonFromEllipseSegment(
4689 aCenter,
4690 aEllipseRect_MS.getWidth() * 0.5,
4691 aEllipseRect_MS.getHeight() * 0.5,
4692 fRadStartAngle,
4693 fRadEndAngle));
4694 aTempPie.append(aCenter);
4695 aPieRect_MS = aTempPie.getB2DRange();
4698 // MS Office uses for mso_sptArc a frame rectangle (=resize handles)
4699 // which encloses only the sector, LibreOffice uses for custom shapes as
4700 // default a frame rectangle, which encloses the entire ellipse. That would
4701 // result in wrong positions in Writer and Calc, see tdf#124029.
4702 // We workaround this problem, by setting a suitable viewBox.
4703 bool bIsImportPPT(GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_PPT);
4704 if (bIsImportPPT || aPieRect_MS.getWidth() == 0 || aPieRect_MS.getHeight() == 0)
4705 { // clear item, so that default from EnhancedCustomShapeGeometry is used
4706 aGeometryItem.ClearPropertyValue(sViewBox);
4708 else
4710 double fX((aPieRect_MS.getMinX() - aEllipseRect_MS.getMinX()) / 2.0);
4711 double fY((aPieRect_MS.getMinY() - aEllipseRect_MS.getMinY()) / 2.0);
4712 css::awt::Rectangle aViewBox_LO; // in LO coordinate system
4713 aViewBox_LO.X = static_cast<sal_Int32>(fX);
4714 aViewBox_LO.Y = static_cast<sal_Int32>(fY);
4715 aViewBox_LO.Width = static_cast<sal_Int32>(aPieRect_MS.getWidth() / 2.0);
4716 aViewBox_LO.Height = static_cast<sal_Int32>(aPieRect_MS.getHeight() / 2.0);
4717 aPropVal.Name = sViewBox;
4718 aPropVal.Value <<= aViewBox_LO;
4719 aGeometryItem.SetPropertyValue(aPropVal);
4722 // aObjData.aBoundRect contains position and size of the sector in (outer)
4723 // logic coordinates, e.g. for PPT in 1/100 mm, for Word in twips.
4724 // For Impress the default viewBox is used, so adapt aObjData.aBoundRect.
4725 tools::Rectangle aOldBoundRect(aObjData.aBoundRect); // backup, needed later on
4726 if (bIsImportPPT)
4728 double fLogicXOfs(0.0); // LogicLeft_LO = LogicLeft_MS + fXLogicOfs
4729 double fLogicYOfs(0.0);
4730 double fLogicPieWidth(aObjData.aBoundRect.getOpenWidth());
4731 double fLogicPieHeight(aObjData.aBoundRect.getOpenHeight());
4732 double fLogicEllipseWidth(0.0); // to be LogicWidth_LO
4733 double fLogicEllipseHeight(0.0);
4734 if (aPieRect_MS.getWidth())
4736 // fXScale = ratio 'logic length' : 'shape internal length'
4737 double fXScale = fLogicPieWidth / aPieRect_MS.getWidth();
4738 if (nSpFlags & ShapeFlag::FlipH)
4739 fLogicXOfs = (aPieRect_MS.getMaxX() - aEllipseRect_MS.getMaxX()) * fXScale;
4740 else
4741 fLogicXOfs = (aEllipseRect_MS.getMinX() - aPieRect_MS.getMinX()) * fXScale;
4742 fLogicEllipseWidth = aEllipseRect_MS.getWidth() * fXScale;
4744 if (aPieRect_MS.getHeight())
4746 double fYScale = fLogicPieHeight / aPieRect_MS.getHeight();
4747 if (nSpFlags & ShapeFlag::FlipV)
4748 fLogicYOfs = (aPieRect_MS.getMaxY() - aEllipseRect_MS.getMaxY()) * fYScale;
4749 else
4750 fLogicYOfs = (aEllipseRect_MS.getMinY() - aPieRect_MS.getMinY()) * fYScale;
4751 fLogicEllipseHeight = aEllipseRect_MS.getHeight() * fYScale;
4753 aObjData.aBoundRect = tools::Rectangle(
4754 Point(aOldBoundRect.Left() + static_cast<sal_Int32>(fLogicXOfs),
4755 aOldBoundRect.Top() + static_cast<sal_Int32>(fLogicYOfs)),
4756 Size(static_cast<sal_Int32>(fLogicEllipseWidth),
4757 static_cast<sal_Int32>(fLogicEllipseHeight)));
4759 // else nothing to do. aObjData.aBoundRect corresponds to changed viewBox.
4761 // creating the text frame -> scaling into (0,0),(21600,21600) destination coordinate system
4762 double fTextFrameScaleX = 0.0;
4763 double fTextFrameScaleY = 0.0;
4764 if (aEllipseRect_MS.getWidth())
4765 fTextFrameScaleX = 21600.0 / aEllipseRect_MS.getWidth();
4766 if (aEllipseRect_MS.getHeight())
4767 fTextFrameScaleY = 21600.0 / aEllipseRect_MS.getHeight();
4769 sal_Int32 nLeft = static_cast<sal_Int32>((aPieRect_MS.getMinX() - aEllipseRect_MS.getMinX()) * fTextFrameScaleX );
4770 sal_Int32 nTop = static_cast<sal_Int32>((aPieRect_MS.getMinY() - aEllipseRect_MS.getMinY()) * fTextFrameScaleY );
4771 sal_Int32 nRight = static_cast<sal_Int32>((aPieRect_MS.getMaxX() - aEllipseRect_MS.getMinX()) * fTextFrameScaleX );
4772 sal_Int32 nBottom= static_cast<sal_Int32>((aPieRect_MS.getMaxY() - aEllipseRect_MS.getMinY()) * fTextFrameScaleY );
4773 css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aTextFrame( 1 );
4774 auto pTextFrame = aTextFrame.getArray();
4775 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pTextFrame[ 0 ].TopLeft.First, nLeft );
4776 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pTextFrame[ 0 ].TopLeft.Second, nTop );
4777 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pTextFrame[ 0 ].BottomRight.First, nRight );
4778 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pTextFrame[ 0 ].BottomRight.Second,nBottom );
4779 PropertyValue aProp;
4780 aProp.Name = "TextFrames";
4781 aProp.Value <<= aTextFrame;
4782 aGeometryItem.SetPropertyValue( sPath, aProp );
4784 // sj: taking care of the different rotation points, since the new arc is having a bigger snaprect
4785 if ( mnFix16Angle )
4787 Degree100 nAngle = mnFix16Angle;
4788 if ( nSpFlags & ShapeFlag::FlipH )
4789 nAngle = 36000_deg100 - nAngle;
4790 if ( nSpFlags & ShapeFlag::FlipV )
4791 nAngle = -nAngle;
4792 double a = toRadians(nAngle);
4793 double ss = sin( a );
4794 double cc = cos( a );
4795 Point aP1( aOldBoundRect.TopLeft() );
4796 Point aC1( aObjData.aBoundRect.Center() );
4797 Point aP2( aOldBoundRect.TopLeft() );
4798 Point aC2( aOldBoundRect.Center() );
4799 RotatePoint( aP1, aC1, ss, cc );
4800 RotatePoint( aP2, aC2, ss, cc );
4801 aObjData.aBoundRect.Move( aP2.X() - aP1.X(), aP2.Y() - aP1.Y() );
4804 // clearing items, so MergeDefaultAttributes will set the corresponding
4805 // defaults from EnhancedCustomShapeGeometry
4806 aGeometryItem.ClearPropertyValue( "Handles" );
4807 aGeometryItem.ClearPropertyValue( "Equations" );
4808 aGeometryItem.ClearPropertyValue( sPath );
4810 static_cast<SdrObjCustomShape*>(xRet.get())->SetMergedItem( aGeometryItem );
4811 static_cast<SdrObjCustomShape*>(xRet.get())->MergeDefaultAttributes();
4813 // now setting a new name, so the above correction is only done once when importing from ms
4814 SdrCustomShapeGeometryItem aGeoName( static_cast<SdrObjCustomShape*>(xRet.get())->GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
4815 aPropVal.Name = "Type";
4816 aPropVal.Value <<= OUString( "mso-spt100" );
4817 aGeoName.SetPropertyValue( aPropVal );
4818 static_cast<SdrObjCustomShape*>(xRet.get())->SetMergedItem( aGeoName );
4820 else
4821 static_cast<SdrObjCustomShape*>(xRet.get())->MergeDefaultAttributes();
4823 xRet->SetSnapRect( aObjData.aBoundRect );
4824 EnhancedCustomShape2d aCustomShape2d(static_cast<SdrObjCustomShape&>(*xRet));
4825 aTextRect = aCustomShape2d.GetTextRect();
4827 if( bIsConnector )
4829 if( nObjectRotation )
4830 xRet->NbcRotate( aObjData.aBoundRect.Center(), nObjectRotation );
4831 // mirrored horizontally?
4832 if ( nSpFlags & ShapeFlag::FlipH )
4834 tools::Rectangle aBndRect(xRet->GetSnapRect());
4835 Point aTop( ( aBndRect.Left() + aBndRect.Right() ) >> 1, aBndRect.Top() );
4836 Point aBottom( aTop.X(), aTop.Y() + 1000 );
4837 xRet->NbcMirror( aTop, aBottom );
4839 // mirrored vertically?
4840 if ( nSpFlags & ShapeFlag::FlipV )
4842 tools::Rectangle aBndRect(xRet->GetSnapRect());
4843 Point aLeft( aBndRect.Left(), ( aBndRect.Top() + aBndRect.Bottom() ) >> 1 );
4844 Point aRight( aLeft.X() + 1000, aLeft.Y() );
4845 xRet->NbcMirror( aLeft, aRight );
4847 basegfx::B2DPolyPolygon aPoly( static_cast<SdrObjCustomShape*>(xRet.get())->GetLineGeometry( true ) );
4849 xRet = new SdrEdgeObj(*pSdrModel);
4850 ApplyAttributes( rSt, aSet, aObjData );
4851 xRet->SetLogicRect( aObjData.aBoundRect );
4852 xRet->SetMergedItemSet(aSet);
4854 // connectors
4855 auto eConnectorStyle = GetPropertyValue(DFF_Prop_cxstyle, mso_cxstyleStraight);
4857 static_cast<SdrEdgeObj*>(xRet.get())->ConnectToNode(true, nullptr);
4858 static_cast<SdrEdgeObj*>(xRet.get())->ConnectToNode(false, nullptr);
4860 Point aPoint1( aObjData.aBoundRect.TopLeft() );
4861 Point aPoint2( aObjData.aBoundRect.BottomRight() );
4863 // pay attention to the rotations
4864 if ( nObjectRotation )
4866 double a = toRadians(nObjectRotation);
4867 Point aCenter( aObjData.aBoundRect.Center() );
4868 double ss = sin(a);
4869 double cc = cos(a);
4871 RotatePoint(aPoint1, aCenter, ss, cc);
4872 RotatePoint(aPoint2, aCenter, ss, cc);
4874 // #i120437# reset rotation, it is part of the path and shall not be applied again
4875 nObjectRotation = 0_deg100;
4878 // rotate/mirror line within the area as we need it
4879 if ( nSpFlags & ShapeFlag::FlipH )
4881 sal_Int32 n = aPoint1.X();
4882 aPoint1.setX( aPoint2.X() );
4883 aPoint2.setX( n );
4885 // #i120437# reset hor flip
4886 nSpFlags &= ~ShapeFlag::FlipH;
4888 if ( nSpFlags & ShapeFlag::FlipV )
4890 sal_Int32 n = aPoint1.Y();
4891 aPoint1.setY( aPoint2.Y() );
4892 aPoint2.setY( n );
4894 // #i120437# reset ver flip
4895 nSpFlags &= ~ShapeFlag::FlipV;
4898 xRet->NbcSetPoint(aPoint1, 0); // start point
4899 xRet->NbcSetPoint(aPoint2, 1); // endpoint
4901 sal_Int32 n1HorzDist, n1VertDist, n2HorzDist, n2VertDist;
4902 n1HorzDist = n1VertDist = n2HorzDist = n2VertDist = 0;
4903 switch( eConnectorStyle )
4905 case mso_cxstyleBent:
4907 aSet.Put( SdrEdgeKindItem( SdrEdgeKind::OrthoLines ) );
4908 n1HorzDist = n1VertDist = n2HorzDist = n2VertDist = 630;
4910 break;
4911 case mso_cxstyleCurved:
4912 aSet.Put( SdrEdgeKindItem( SdrEdgeKind::Bezier ) );
4913 break;
4914 default: // mso_cxstyleStraight || mso_cxstyleNone
4915 aSet.Put( SdrEdgeKindItem( SdrEdgeKind::OneLine ) );
4916 break;
4918 aSet.Put( SdrEdgeNode1HorzDistItem( n1HorzDist ) );
4919 aSet.Put( SdrEdgeNode1VertDistItem( n1VertDist ) );
4920 aSet.Put( SdrEdgeNode2HorzDistItem( n2HorzDist ) );
4921 aSet.Put( SdrEdgeNode2VertDistItem( n2VertDist ) );
4923 static_cast<SdrEdgeObj*>(xRet.get())->SetEdgeTrackPath( aPoly );
4924 xRet->SetMergedItemSet(aSet);
4926 if ( aObjData.eShapeType == mso_sptLine )
4928 xRet->SetMergedItemSet(aSet);
4929 static_cast<SdrObjCustomShape*>(xRet.get())->MergeDefaultAttributes();
4934 if (xRet)
4936 if( nObjectRotation )
4937 xRet->NbcRotate( aObjData.aBoundRect.Center(), nObjectRotation );
4938 // mirrored horizontally?
4939 if ( nSpFlags & ShapeFlag::FlipH )
4941 tools::Rectangle aBndRect(xRet->GetSnapRect());
4942 Point aTop( ( aBndRect.Left() + aBndRect.Right() ) >> 1, aBndRect.Top() );
4943 Point aBottom( aTop.X(), aTop.Y() + 1000 );
4944 xRet->NbcMirror(aTop, aBottom);
4946 // mirrored vertically?
4947 if ( nSpFlags & ShapeFlag::FlipV )
4949 tools::Rectangle aBndRect(xRet->GetSnapRect());
4950 Point aLeft( aBndRect.Left(), ( aBndRect.Top() + aBndRect.Bottom() ) >> 1 );
4951 Point aRight( aLeft.X() + 1000, aLeft.Y() );
4952 xRet->NbcMirror(aLeft, aRight);
4958 // #i51348# #118052# name of the shape
4959 if (xRet)
4961 OUString aObjName = GetPropertyString( DFF_Prop_wzName, rSt );
4962 if( !aObjName.isEmpty() )
4963 xRet->SetName(aObjName);
4966 xRet = ProcessObj(rSt, aObjData, rClientData, aTextRect, xRet.get());
4968 if (xRet)
4970 sal_Int32 nGroupProperties( GetPropertyValue( DFF_Prop_fPrint, 0 ) );
4971 const bool bVisible = ( ( nGroupProperties & 2 ) == 0 );
4972 xRet->SetVisible( bVisible );
4973 // In Excel hidden means not printed
4974 if ( !bVisible )
4976 xRet->SetPrintable(false);
4978 else
4980 // This property isn't used in Excel anymore, leaving it for legacy reasons
4981 xRet->SetPrintable( ( nGroupProperties & 1 ) != 0 );
4985 //Import alt text as description
4986 if (xRet && SeekToContent(DFF_Prop_wzDescription, rSt))
4988 OUString aAltText = MSDFFReadZString(rSt, GetPropertyValue(DFF_Prop_wzDescription, 0), true);
4989 xRet->SetDescription(aAltText);
4992 // If this shape opens a new group, push back its object data because
4993 // finalization will be called when nested objects have been imported;
4994 // otherwise, just finalize here
4995 if (o3tl::make_unsigned(nCalledByGroup) > maPendingGroupData.size())
4997 auto xHdClone = std::make_shared<DffRecordHeader>(aObjData.rSpHd);
4998 maPendingGroupData.emplace_back(DffObjData(xHdClone, aObjData), xHdClone );
5000 else
5002 xRet = FinalizeObj(aObjData, xRet.get());
5004 return xRet;
5007 tools::Rectangle SvxMSDffManager::GetGlobalChildAnchor( const DffRecordHeader& rHd, SvStream& rSt, tools::Rectangle& aClientRect )
5009 tools::Rectangle aChildAnchor;
5010 if (!rHd.SeekToContent(rSt))
5011 return aChildAnchor;
5013 bool bIsClientRectRead = false;
5014 while ( ( rSt.GetError() == ERRCODE_NONE ) && ( rSt.Tell() < rHd.GetRecEndFilePos() ) )
5016 DffRecordHeader aShapeHd;
5017 if (!ReadDffRecordHeader(rSt, aShapeHd))
5018 break;
5019 if ( ( aShapeHd.nRecType == DFF_msofbtSpContainer ) ||
5020 ( aShapeHd.nRecType == DFF_msofbtSpgrContainer ) )
5022 DffRecordHeader aShapeHd2( aShapeHd );
5023 if ( aShapeHd.nRecType == DFF_msofbtSpgrContainer )
5024 ReadDffRecordHeader( rSt, aShapeHd2 );
5025 while (rSt.good() && rSt.Tell() < aShapeHd2.GetRecEndFilePos())
5027 DffRecordHeader aShapeAtom;
5028 if (!ReadDffRecordHeader(rSt, aShapeAtom))
5029 break;
5031 if ( aShapeAtom.nRecType == DFF_msofbtClientAnchor )
5033 if ( GetSvxMSDffSettings() & SVXMSDFF_SETTINGS_IMPORT_PPT )
5035 sal_Int32 l(0), t(0), r(0), b(0);
5036 if ( aShapeAtom.nRecLen == 16 )
5038 rSt.ReadInt32( l ).ReadInt32( t ).ReadInt32( r ).ReadInt32( b );
5040 else
5042 sal_Int16 ls(0), ts(0), rs(0), bs(0);
5043 rSt.ReadInt16( ts ).ReadInt16( ls ).ReadInt16( rs ).ReadInt16( bs ); // the order of coordinates is a bit strange...
5044 l = ls;
5045 t = ts;
5046 r = rs;
5047 b = bs;
5049 Scale( l );
5050 Scale( t );
5051 Scale( r );
5052 Scale( b );
5053 if ( bIsClientRectRead )
5055 tools::Rectangle aChild( l, t, r, b );
5056 aChildAnchor.Union( aChild );
5058 else
5060 aClientRect = tools::Rectangle( l, t, r, b );
5061 bIsClientRectRead = true;
5064 break;
5066 else if ( aShapeAtom.nRecType == DFF_msofbtChildAnchor )
5068 sal_Int32 l(0), o(0), r(0), u(0);
5069 rSt.ReadInt32( l ).ReadInt32( o ).ReadInt32( r ).ReadInt32( u );
5070 Scale( l );
5071 Scale( o );
5072 Scale( r );
5073 Scale( u );
5074 tools::Rectangle aChild( l, o, r, u );
5075 aChildAnchor.Union( aChild );
5076 break;
5078 if (!aShapeAtom.SeekToEndOfRecord(rSt))
5079 break;
5082 if (!aShapeHd.SeekToEndOfRecord(rSt))
5083 break;
5085 return aChildAnchor;
5088 void SvxMSDffManager::GetGroupAnchors( const DffRecordHeader& rHd, SvStream& rSt,
5089 tools::Rectangle& rGroupClientAnchor, tools::Rectangle& rGroupChildAnchor,
5090 const tools::Rectangle& rClientRect, const tools::Rectangle& rGlobalChildRect )
5092 if (!rHd.SeekToContent(rSt))
5093 return;
5095 bool bFirst = true;
5096 DffRecordHeader aShapeHd;
5097 while (rSt.good() && rSt.Tell() < rHd.GetRecEndFilePos())
5099 if (!ReadDffRecordHeader(rSt, aShapeHd))
5100 break;
5101 if ( ( aShapeHd.nRecType == DFF_msofbtSpContainer ) ||
5102 ( aShapeHd.nRecType == DFF_msofbtSpgrContainer ) )
5104 DffRecordHeader aShapeHd2( aShapeHd );
5105 if ( aShapeHd.nRecType == DFF_msofbtSpgrContainer )
5106 ReadDffRecordHeader( rSt, aShapeHd2 );
5107 while (rSt.good() && rSt.Tell() < aShapeHd2.GetRecEndFilePos())
5109 DffRecordHeader aShapeAtom;
5110 if (!ReadDffRecordHeader(rSt, aShapeAtom))
5111 break;
5112 if ( aShapeAtom.nRecType == DFF_msofbtChildAnchor )
5114 sal_Int32 l(0), o(0), r(0), u(0);
5115 rSt.ReadInt32( l ).ReadInt32( o ).ReadInt32( r ).ReadInt32( u );
5116 Scale( l );
5117 Scale( o );
5118 Scale( r );
5119 Scale( u );
5120 tools::Rectangle aChild( l, o, r, u );
5122 if ( bFirst )
5124 if ( !rGlobalChildRect.IsEmpty() && !rClientRect.IsEmpty() && rGlobalChildRect.GetWidth() && rGlobalChildRect.GetHeight() )
5126 double fWidth = o3tl::saturating_sub(r, l);
5127 double fHeight= o3tl::saturating_sub(u, o);
5128 double fXScale = static_cast<double>(rClientRect.GetWidth()) / static_cast<double>(rGlobalChildRect.GetWidth());
5129 double fYScale = static_cast<double>(rClientRect.GetHeight()) / static_cast<double>(rGlobalChildRect.GetHeight());
5130 double fl = ( ( l - rGlobalChildRect.Left() ) * fXScale ) + rClientRect.Left();
5131 double fo = ( ( o - rGlobalChildRect.Top() ) * fYScale ) + rClientRect.Top();
5132 fWidth *= fXScale;
5133 fHeight *= fYScale;
5134 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 ) ) );
5136 bFirst = false;
5138 else
5139 rGroupChildAnchor.Union( aChild );
5140 break;
5142 if (!aShapeAtom.SeekToEndOfRecord(rSt))
5143 break;
5146 if (!aShapeHd.SeekToEndOfRecord(rSt))
5147 break;
5151 SvxMSDffImportRec* SvxMSDffImportData::find(const SdrObject* pObj)
5153 auto it = m_ObjToRecMap.find(pObj);
5154 if (it != m_ObjToRecMap.end())
5155 return it->second;
5156 return nullptr;
5159 void SvxMSDffImportData::insert(std::unique_ptr<SvxMSDffImportRec> pImpRec)
5161 auto aRet = m_Records.insert(std::move(pImpRec));
5162 bool bSuccess = aRet.second;
5163 if (bSuccess)
5165 SvxMSDffImportRec* pRec = aRet.first->get();
5166 m_ObjToRecMap[pRec->pObj.get()] = pRec;
5170 void SvxMSDffImportData::NotifyFreeObj(SdrObject* pObj)
5172 if (SvxMSDffImportRec* pRecord = find(pObj))
5174 m_ObjToRecMap.erase(pObj);
5175 pRecord->pObj = nullptr;
5179 void SvxMSDffManager::NotifyFreeObj(SvxMSDffClientData& rData, SdrObject* pObj)
5181 if (SdrObjGroup* pGroup = dynamic_cast<SdrObjGroup*>(pObj))
5183 SdrObjList* pSubList = pGroup->GetSubList();
5184 size_t nObjCount = pSubList->GetObjCount();
5185 for (size_t i = 0; i < nObjCount; ++i)
5186 NotifyFreeObj(rData, pSubList->GetObj(i));
5189 rData.NotifyFreeObj(pObj);
5192 void SvxMSDffManager::FreeObj(SvxMSDffClientData& rData, SdrObject* pObj)
5194 NotifyFreeObj(rData, pObj);
5197 rtl::Reference<SdrObject> SvxMSDffManager::ProcessObj(SvStream& rSt,
5198 DffObjData& rObjData,
5199 SvxMSDffClientData& rData,
5200 tools::Rectangle& rTextRect,
5201 SdrObject* pObj1
5204 rtl::Reference<SdrObject> pObj = pObj1;
5205 if( !rTextRect.IsEmpty() )
5207 SvxMSDffImportData& rImportData = static_cast<SvxMSDffImportData&>(rData);
5208 SvxMSDffImportRec* pImpRec = new SvxMSDffImportRec;
5209 bool bDeleteImpRec = true;
5210 SvxMSDffImportRec* pTextImpRec = pImpRec;
5211 bool bDeleteTextImpRec = false;
5213 // fill Import Record with data
5214 pImpRec->nShapeId = rObjData.nShapeId;
5215 pImpRec->eShapeType = rObjData.eShapeType;
5217 auto eWrapMode = GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare);
5218 rObjData.bClientAnchor = maShapeRecords.SeekToContent( rSt,
5219 DFF_msofbtClientAnchor,
5220 SEEK_FROM_CURRENT_AND_RESTART );
5221 if( rObjData.bClientAnchor )
5222 ProcessClientAnchor( rSt,
5223 maShapeRecords.Current()->nRecLen,
5224 pImpRec->pClientAnchorBuffer, pImpRec->nClientAnchorLen );
5226 rObjData.bClientData = maShapeRecords.SeekToContent( rSt,
5227 DFF_msofbtClientData,
5228 SEEK_FROM_CURRENT_AND_RESTART );
5229 if( rObjData.bClientData )
5230 ProcessClientData( rSt,
5231 maShapeRecords.Current()->nRecLen,
5232 pImpRec->pClientDataBuffer, pImpRec->nClientDataLen );
5235 // process user (== Winword) defined parameters in 0xF122 record
5236 if( maShapeRecords.SeekToContent( rSt,
5237 DFF_msofbtUDefProp,
5238 SEEK_FROM_CURRENT_AND_RESTART )
5239 && maShapeRecords.Current()->nRecLen )
5241 sal_uInt32 nBytesLeft = maShapeRecords.Current()->nRecLen;
5242 while( 5 < nBytesLeft )
5244 sal_uInt16 nPID(0);
5245 rSt.ReadUInt16(nPID);
5246 if (!rSt.good())
5247 break;
5248 sal_uInt32 nUDData(0);
5249 rSt.ReadUInt32(nUDData);
5250 switch (nPID)
5252 case 0x038F: pImpRec->nXAlign = nUDData; break;
5253 case 0x0390:
5254 pImpRec->nXRelTo = nUDData;
5255 break;
5256 case 0x0391: pImpRec->nYAlign = nUDData; break;
5257 case 0x0392:
5258 pImpRec->nYRelTo = nUDData;
5259 break;
5260 case 0x03BF: pImpRec->nGroupShapeBooleanProperties = nUDData; break;
5261 case 0x0393:
5262 // This seems to correspond to o:hrpct from .docx (even including
5263 // the difference that it's in 0.1% even though the .docx spec
5264 // says it's in 1%).
5265 pImpRec->relativeHorizontalWidth = nUDData;
5266 break;
5267 case 0x0394:
5268 // And this is really just a guess, but a mere presence of this
5269 // flag makes a horizontal rule be as wide as the page (unless
5270 // overridden by something), so it probably matches o:hr from .docx.
5271 pImpRec->isHorizontalRule = true;
5272 break;
5274 if (!rSt.good())
5275 break;
5276 nBytesLeft -= 6;
5280 // text frame, also Title or Outline
5281 rtl::Reference<SdrObject> pOrgObj = pObj;
5282 rtl::Reference<SdrRectObj> pTextObj;
5283 sal_uInt32 nTextId = GetPropertyValue( DFF_Prop_lTxid, 0 );
5284 if( nTextId )
5286 SfxItemSet aSet( pSdrModel->GetItemPool() );
5288 //Originally anything that as a mso_sptTextBox was created as a
5289 //textbox, this was changed for #88277# to be created as a simple
5290 //rect to keep impress happy. For the rest of us we'd like to turn
5291 //it back into a textbox again.
5292 bool bTextFrame = (pImpRec->eShapeType == mso_sptTextBox);
5293 if (!bTextFrame)
5295 //Either
5296 //a) it's a simple text object or
5297 //b) it's a rectangle with text and square wrapping.
5298 bTextFrame =
5300 (pImpRec->eShapeType == mso_sptTextSimple) ||
5302 (pImpRec->eShapeType == mso_sptRectangle)
5303 && (eWrapMode == mso_wrapSquare)
5304 && ShapeHasText(pImpRec->nShapeId, rObjData.rSpHd.GetRecBegFilePos() )
5309 if (bTextFrame)
5311 pObj = nullptr;
5312 pOrgObj = nullptr;
5315 // Distance of Textbox to its surrounding Customshape
5316 sal_Int32 nTextLeft = GetPropertyValue( DFF_Prop_dxTextLeft, 91440L);
5317 sal_Int32 nTextRight = GetPropertyValue( DFF_Prop_dxTextRight, 91440L );
5318 sal_Int32 nTextTop = GetPropertyValue( DFF_Prop_dyTextTop, 45720L );
5319 sal_Int32 nTextBottom = GetPropertyValue( DFF_Prop_dyTextBottom, 45720L );
5321 ScaleEmu( nTextLeft );
5322 ScaleEmu( nTextRight );
5323 ScaleEmu( nTextTop );
5324 ScaleEmu( nTextBottom );
5326 Degree100 nTextRotationAngle(0);
5327 bool bVerticalText = false;
5328 if ( IsProperty( DFF_Prop_txflTextFlow ) )
5330 auto eTextFlow = GetPropertyValue(DFF_Prop_txflTextFlow, 0) & 0xFFFF;
5331 switch( eTextFlow )
5333 case mso_txflBtoT:
5334 nTextRotationAngle = 9000_deg100;
5335 break;
5336 case mso_txflVertN:
5337 case mso_txflTtoBN:
5338 nTextRotationAngle = 27000_deg100;
5339 break;
5340 case mso_txflTtoBA:
5341 bVerticalText = true;
5342 break;
5343 case mso_txflHorzA:
5344 bVerticalText = true;
5345 nTextRotationAngle = 9000_deg100;
5346 break;
5347 case mso_txflHorzN:
5348 default :
5349 break;
5353 if (nTextRotationAngle)
5355 switch (nTextRotationAngle.get())
5357 case 9000:
5359 tools::Long nWidth = rTextRect.GetWidth();
5360 rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() );
5361 rTextRect.SetBottom( rTextRect.Top() + nWidth );
5363 sal_Int32 nOldTextLeft = nTextLeft;
5364 sal_Int32 nOldTextRight = nTextRight;
5365 sal_Int32 nOldTextTop = nTextTop;
5366 sal_Int32 nOldTextBottom = nTextBottom;
5368 nTextLeft = nOldTextBottom;
5369 nTextRight = nOldTextTop;
5370 nTextTop = nOldTextLeft;
5371 nTextBottom = nOldTextRight;
5373 break;
5374 case 27000:
5376 tools::Long nWidth = rTextRect.GetWidth();
5377 rTextRect.SetRight( rTextRect.Left() + rTextRect.GetHeight() );
5378 rTextRect.SetBottom( rTextRect.Top() + nWidth );
5380 sal_Int32 nOldTextLeft = nTextLeft;
5381 sal_Int32 nOldTextRight = nTextRight;
5382 sal_Int32 nOldTextTop = nTextTop;
5383 sal_Int32 nOldTextBottom = nTextBottom;
5385 nTextLeft = nOldTextTop;
5386 nTextRight = nOldTextBottom;
5387 nTextTop = nOldTextRight;
5388 nTextBottom = nOldTextLeft;
5390 break;
5394 pTextObj = new SdrRectObj(
5395 *pSdrModel,
5396 SdrObjKind::Text,
5397 rTextRect);
5398 pTextImpRec = new SvxMSDffImportRec(*pImpRec);
5399 bDeleteTextImpRec = true;
5401 // the vertical paragraph indents are part of the BoundRect,
5402 // here we 'remove' them by calculating
5403 tools::Rectangle aNewRect(rTextRect);
5404 aNewRect.AdjustBottom( -(nTextTop + nTextBottom) );
5405 aNewRect.AdjustRight( -(nTextLeft + nTextRight) );
5407 // Only if it's a simple textbox may Writer replace
5408 // the object with a frame, otherwise
5409 if( bTextFrame )
5411 auto const pTmpRec = std::make_shared<SvxMSDffShapeInfo>(0, pImpRec->nShapeId);
5413 SvxMSDffShapeInfos_ById::const_iterator const it =
5414 m_xShapeInfosById->find(pTmpRec);
5415 if (it != m_xShapeInfosById->end())
5417 SvxMSDffShapeInfo& rInfo = **it;
5418 pTextImpRec->bReplaceByFly = rInfo.bReplaceByFly;
5422 if( !pObj )
5423 ApplyAttributes( rSt, aSet, rObjData );
5425 bool bFitText = false;
5426 if (GetPropertyValue(DFF_Prop_FitTextToShape, 0) & 2)
5428 aSet.Put( makeSdrTextAutoGrowHeightItem( true ) );
5429 aSet.Put( makeSdrTextMinFrameHeightItem(
5430 aNewRect.Bottom() - aNewRect.Top() ) );
5431 aSet.Put( makeSdrTextMinFrameWidthItem(
5432 aNewRect.Right() - aNewRect.Left() ) );
5433 bFitText = true;
5435 else
5437 aSet.Put( makeSdrTextAutoGrowHeightItem( false ) );
5438 aSet.Put( makeSdrTextAutoGrowWidthItem( false ) );
5441 switch (GetPropertyValue(DFF_Prop_WrapText, mso_wrapSquare))
5443 case mso_wrapNone :
5444 aSet.Put( makeSdrTextAutoGrowWidthItem( true ) );
5445 if (bFitText)
5447 //can't do autowidth in flys #i107184#
5448 pTextImpRec->bReplaceByFly = false;
5450 break;
5451 case mso_wrapByPoints :
5452 aSet.Put( makeSdrTextContourFrameItem( true ) );
5453 break;
5454 default: break;
5457 // set margins at the border of the textbox
5458 aSet.Put( makeSdrTextLeftDistItem( nTextLeft ) );
5459 aSet.Put( makeSdrTextRightDistItem( nTextRight ) );
5460 aSet.Put( makeSdrTextUpperDistItem( nTextTop ) );
5461 aSet.Put( makeSdrTextLowerDistItem( nTextBottom ) );
5462 pTextImpRec->nDxTextLeft = nTextLeft;
5463 pTextImpRec->nDyTextTop = nTextTop;
5464 pTextImpRec->nDxTextRight = nTextRight;
5465 pTextImpRec->nDyTextBottom = nTextBottom;
5467 // read text anchor
5468 if ( IsProperty( DFF_Prop_anchorText ) )
5470 auto eTextAnchor = GetPropertyValue(DFF_Prop_anchorText, 0);
5472 SdrTextVertAdjust eTVA = SDRTEXTVERTADJUST_CENTER;
5473 bool bTVASet(false);
5474 bool bTHASet(false);
5476 switch( eTextAnchor )
5478 case mso_anchorTop:
5480 eTVA = SDRTEXTVERTADJUST_TOP;
5481 bTVASet = true;
5483 break;
5484 case mso_anchorTopCentered:
5486 eTVA = SDRTEXTVERTADJUST_TOP;
5487 bTVASet = true;
5488 bTHASet = true;
5490 break;
5492 case mso_anchorMiddle:
5493 bTVASet = true;
5494 break;
5495 case mso_anchorMiddleCentered:
5497 bTVASet = true;
5498 bTHASet = true;
5500 break;
5501 case mso_anchorBottom:
5503 eTVA = SDRTEXTVERTADJUST_BOTTOM;
5504 bTVASet = true;
5506 break;
5507 case mso_anchorBottomCentered:
5509 eTVA = SDRTEXTVERTADJUST_BOTTOM;
5510 bTVASet = true;
5511 bTHASet = true;
5513 break;
5514 default : break;
5516 // insert
5517 if ( bTVASet )
5518 aSet.Put( SdrTextVertAdjustItem( eTVA ) );
5519 if ( bTHASet )
5520 aSet.Put( SdrTextHorzAdjustItem( SDRTEXTHORZADJUST_CENTER ) );
5523 pTextObj->SetMergedItemSet(aSet);
5525 if (bVerticalText)
5526 pTextObj->SetVerticalWriting(true);
5528 if (nTextRotationAngle)
5530 tools::Long nMinWH = rTextRect.GetWidth() < rTextRect.GetHeight() ?
5531 rTextRect.GetWidth() : rTextRect.GetHeight();
5532 nMinWH /= 2;
5533 Point aPivot(rTextRect.TopLeft());
5534 aPivot.AdjustX(nMinWH );
5535 aPivot.AdjustY(nMinWH );
5536 pTextObj->SdrAttrObj::NbcRotate(aPivot, nTextRotationAngle);
5539 // rotate text with shape?
5540 if ( mnFix16Angle )
5542 double a = toRadians(mnFix16Angle);
5543 pTextObj->NbcRotate( rObjData.aBoundRect.Center(), mnFix16Angle,
5544 sin( a ), cos( a ) );
5547 if( !pObj )
5549 pObj = pTextObj.get();
5551 else
5553 if( pTextObj.get() != pObj.get() )
5555 rtl::Reference<SdrObject> pGroup = new SdrObjGroup(*pSdrModel);
5556 pGroup->GetSubList()->NbcInsertObject( pObj.get() );
5557 pGroup->GetSubList()->NbcInsertObject( pTextObj.get() );
5558 if (pOrgObj == pObj)
5559 pOrgObj = pGroup;
5560 else
5561 pOrgObj = pObj;
5562 pObj = pGroup.get();
5566 else if( !pObj )
5568 // simple rectangular objects are ignored by ImportObj() :-(
5569 // this is OK for Draw but not for Calc and Writer
5570 // cause here these objects have a default border
5571 pObj = new SdrRectObj(
5572 *pSdrModel,
5573 rTextRect);
5575 pOrgObj = pObj;
5576 SfxItemSet aSet( pSdrModel->GetItemPool() );
5577 ApplyAttributes( rSt, aSet, rObjData );
5579 SfxItemState eState = aSet.GetItemState( XATTR_FILLCOLOR );
5580 if( SfxItemState::DEFAULT == eState )
5581 aSet.Put( XFillColorItem( OUString(), mnDefaultColor ) );
5582 pObj->SetMergedItemSet(aSet);
5585 //Means that fBehindDocument is set
5586 if (GetPropertyValue(DFF_Prop_fPrint, 0) & 0x20)
5587 pImpRec->bDrawHell = true;
5588 else
5589 pImpRec->bDrawHell = false;
5590 if (GetPropertyValue(DFF_Prop_fPrint, 0) & 0x02)
5591 pImpRec->bHidden = true;
5592 pTextImpRec->bDrawHell = pImpRec->bDrawHell;
5593 pTextImpRec->bHidden = pImpRec->bHidden;
5594 pImpRec->nNextShapeId = GetPropertyValue( DFF_Prop_hspNext, 0 );
5595 pTextImpRec->nNextShapeId=pImpRec->nNextShapeId;
5597 if ( nTextId )
5599 pTextImpRec->aTextId.nTxBxS = static_cast<sal_uInt16>( nTextId >> 16 );
5600 pTextImpRec->aTextId.nSequence = static_cast<sal_uInt16>(nTextId);
5603 pTextImpRec->nDxWrapDistLeft = GetPropertyValue(
5604 DFF_Prop_dxWrapDistLeft, 114935L ) / 635L;
5605 pTextImpRec->nDyWrapDistTop = GetPropertyValue(
5606 DFF_Prop_dyWrapDistTop, 0 ) / 635L;
5607 pTextImpRec->nDxWrapDistRight = GetPropertyValue(
5608 DFF_Prop_dxWrapDistRight, 114935L ) / 635L;
5609 pTextImpRec->nDyWrapDistBottom = GetPropertyValue(
5610 DFF_Prop_dyWrapDistBottom, 0 ) / 635L;
5611 // 16.16 fraction times total image width or height, as appropriate.
5613 if (SeekToContent(DFF_Prop_pWrapPolygonVertices, rSt))
5615 pTextImpRec->pWrapPolygon.reset();
5616 sal_uInt16 nNumElemVert(0), nNumElemMemVert(0), nElemSizeVert(8);
5617 rSt.ReadUInt16( nNumElemVert ).ReadUInt16( nNumElemMemVert ).ReadUInt16( nElemSizeVert );
5618 // If this value is 0xFFF0 then this record is an array of truncated 8 byte elements. Only the 4
5619 // low-order bytes are recorded
5620 if (nElemSizeVert == 0xFFF0)
5621 nElemSizeVert = 4;
5623 // sanity check that the stream is long enough to fulfill nNumElemVert * nElemSizeVert;
5624 bool bOk = nElemSizeVert && (rSt.remainingSize() / nElemSizeVert >= nNumElemVert);
5625 if (bOk)
5627 pTextImpRec->pWrapPolygon = tools::Polygon(nNumElemVert);
5628 for (sal_uInt16 i = 0; i < nNumElemVert; ++i)
5630 sal_Int32 nX(0), nY(0);
5631 if (nElemSizeVert == 8)
5632 rSt.ReadInt32( nX ).ReadInt32( nY );
5633 else
5635 sal_Int16 nSmallX(0), nSmallY(0);
5636 rSt.ReadInt16( nSmallX ).ReadInt16( nSmallY );
5637 nX = nSmallX;
5638 nY = nSmallY;
5640 (*(pTextImpRec->pWrapPolygon))[i].setX( nX );
5641 (*(pTextImpRec->pWrapPolygon))[i].setY( nY );
5646 pImpRec->nCropFromTop = GetPropertyValue(
5647 DFF_Prop_cropFromTop, 0 );
5648 pImpRec->nCropFromBottom = GetPropertyValue(
5649 DFF_Prop_cropFromBottom, 0 );
5650 pImpRec->nCropFromLeft = GetPropertyValue(
5651 DFF_Prop_cropFromLeft, 0 );
5652 pImpRec->nCropFromRight = GetPropertyValue(
5653 DFF_Prop_cropFromRight, 0 );
5655 pImpRec->bVFlip = bool(rObjData.nSpFlags & ShapeFlag::FlipV);
5656 pImpRec->bHFlip = bool(rObjData.nSpFlags & ShapeFlag::FlipH);
5658 sal_uInt32 nLineFlags = GetPropertyValue( DFF_Prop_fNoLineDrawDash, 0 );
5659 pImpRec->eLineStyle = (nLineFlags & 8)
5660 ? static_cast<MSO_LineStyle>(GetPropertyValue(
5661 DFF_Prop_lineStyle,
5662 mso_lineSimple ))
5663 : MSO_LineStyle_NONE;
5664 pTextImpRec->eLineStyle = pImpRec->eLineStyle;
5666 pImpRec->eLineDashing = static_cast<MSO_LineDashing>(GetPropertyValue(
5667 DFF_Prop_lineDashing, mso_lineSolid ));
5668 pTextImpRec->eLineDashing = pImpRec->eLineDashing;
5670 if( pImpRec->nShapeId )
5672 // amend the import record list
5673 if( pOrgObj )
5675 pImpRec->pObj = pOrgObj.get();
5676 rImportData.insert(std::unique_ptr<SvxMSDffImportRec>(pImpRec));
5677 bDeleteImpRec = false;
5678 if (pImpRec == pTextImpRec)
5679 bDeleteTextImpRec = false;
5682 if( pTextObj && (pOrgObj != pTextObj) )
5684 // Modify ShapeId (must be unique)
5685 pImpRec->nShapeId |= 0x8000000;
5686 pTextImpRec->pObj = pTextObj.get();
5687 rImportData.insert(std::unique_ptr<SvxMSDffImportRec>(pTextImpRec));
5688 bDeleteTextImpRec = false;
5689 if (pTextImpRec == pImpRec)
5690 bDeleteImpRec = false;
5693 // entry in the z-order-list in order to complement the pointer to this object
5694 /*Only store objects which are not deep inside the tree*/
5695 if( ( rObjData.nCalledByGroup == 0 )
5697 ( (rObjData.nSpFlags & ShapeFlag::Group)
5698 && (rObjData.nCalledByGroup < 2) )
5700 StoreShapeOrder( pImpRec->nShapeId,
5701 ( static_cast<sal_uLong>(pImpRec->aTextId.nTxBxS) << 16 )
5702 + pImpRec->aTextId.nSequence, pObj.get() );
5705 if (bDeleteImpRec)
5706 delete pImpRec;
5708 if (bDeleteTextImpRec)
5709 delete pTextImpRec;
5712 return pObj;
5715 SdrObject* SvxMSDffManager::FinalizeObj(DffObjData& /* rObjData */, SdrObject* pObj)
5717 return pObj;
5721 void SvxMSDffManager::StoreShapeOrder(sal_uLong nId,
5722 sal_uLong nTxBx,
5723 SdrObject* pObject,
5724 SwFlyFrameFormat* pFly) const
5726 for (const auto& pOrder : m_aShapeOrders)
5728 if (pOrder->nShapeId == nId)
5730 pOrder->nTxBxComp = nTxBx;
5731 pOrder->pObj = pObject;
5732 pOrder->pFly = pFly;
5738 void SvxMSDffManager::ExchangeInShapeOrder( SdrObject const * pOldObject,
5739 sal_uLong nTxBx,
5740 SdrObject* pObject) const
5742 for (const auto& pOrder : m_aShapeOrders)
5744 if (pOrder->pObj == pOldObject)
5746 pOrder->pFly = nullptr;
5747 pOrder->pObj = pObject;
5748 pOrder->nTxBxComp = nTxBx;
5754 void SvxMSDffManager::RemoveFromShapeOrder( SdrObject const * pObject ) const
5756 for (const auto& pOrder : m_aShapeOrders)
5758 if (pOrder->pObj == pObject)
5760 pOrder->pObj = nullptr;
5761 pOrder->pFly = nullptr;
5762 pOrder->nTxBxComp = 0;
5768 // exported class: Public Methods
5770 SvxMSDffManager::SvxMSDffManager(SvStream& rStCtrl_,
5771 OUString aBaseURL,
5772 sal_uInt32 nOffsDgg_,
5773 SvStream* pStData_,
5774 SdrModel* pSdrModel_,// see SetModel() below
5775 tools::Long nApplicationScale,
5776 Color mnDefaultColor_,
5777 SvStream* pStData2_,
5778 bool bSkipImages )
5779 :DffPropertyReader( *this ),
5780 m_pBLIPInfos( new SvxMSDffBLIPInfos ),
5781 m_xShapeInfosByTxBxComp( new SvxMSDffShapeInfos_ByTxBxComp ),
5782 nOffsDgg( nOffsDgg_ ),
5783 nBLIPCount( USHRT_MAX ), // initialize with error, since we first check if the
5784 nGroupShapeFlags(ShapeFlag::NONE), // ensure initialization here, as some corrupted
5785 // files may yield to this being uninitialized
5786 maBaseURL(std::move( aBaseURL )),
5787 mnIdClusters(0),
5788 rStCtrl( rStCtrl_ ),
5789 pStData( pStData_ ),
5790 pStData2( pStData2_ ),
5791 nSvxMSDffSettings( 0 ),
5792 nSvxMSDffOLEConvFlags( 0 ),
5793 mnDefaultColor( mnDefaultColor_),
5794 mbSkipImages (bSkipImages)
5796 SetModel( pSdrModel_, nApplicationScale );
5798 // remember FilePos of the stream(s)
5799 sal_uInt64 nOldPosCtrl = rStCtrl.Tell();
5800 sal_uInt64 nOldPosData = pStData ? pStData->Tell() : nOldPosCtrl;
5802 // if no data stream is given we assume that the BLIPs
5803 // are in the control stream
5804 if( !pStData )
5805 pStData = &rStCtrl;
5807 SetDefaultPropSet( rStCtrl, nOffsDgg );
5809 // read control stream, if successful set nBLIPCount
5810 GetCtrlData( nOffsDgg );
5812 // check Text-Box-Story-Chain-Infos
5813 CheckTxBxStoryChain();
5815 // restore old FilePos of the stream(s)
5816 rStCtrl.Seek( nOldPosCtrl );
5817 if( &rStCtrl != pStData )
5818 pStData->Seek( nOldPosData );
5821 SvxMSDffManager::SvxMSDffManager( SvStream& rStCtrl_, OUString aBaseURL )
5822 :DffPropertyReader( *this ),
5823 m_pBLIPInfos( new SvxMSDffBLIPInfos ),
5824 m_xShapeInfosByTxBxComp( new SvxMSDffShapeInfos_ByTxBxComp ),
5825 nOffsDgg( 0 ),
5826 nBLIPCount( USHRT_MAX ), // initialize with error, since we first have to check
5827 nGroupShapeFlags(ShapeFlag::NONE),
5828 maBaseURL(std::move( aBaseURL )),
5829 mnIdClusters(0),
5830 rStCtrl( rStCtrl_ ),
5831 pStData( nullptr ),
5832 pStData2( nullptr ),
5833 nSvxMSDffSettings( 0 ),
5834 nSvxMSDffOLEConvFlags( 0 ),
5835 mnDefaultColor( COL_DEFAULT ),
5836 mbSkipImages(false)
5838 SetModel( nullptr, 0 );
5841 SvxMSDffManager::~SvxMSDffManager()
5845 void SvxMSDffManager::InitSvxMSDffManager( sal_uInt32 nOffsDgg_, SvStream* pStData_, sal_uInt32 nOleConvFlags )
5847 nOffsDgg = nOffsDgg_;
5848 pStData = pStData_;
5849 nSvxMSDffOLEConvFlags = nOleConvFlags;
5851 // remember FilePos of the stream(s)
5852 sal_uInt64 nOldPosCtrl = rStCtrl.Tell();
5854 SetDefaultPropSet( rStCtrl, nOffsDgg );
5856 // insert fidcl cluster table
5857 GetFidclData( nOffsDgg );
5859 // read control stream, if successful, set nBLIPCount
5860 GetCtrlData( nOffsDgg );
5862 // check Text-Box-Story-Chain-Infos
5863 CheckTxBxStoryChain();
5865 // restore old FilePos of the stream(s)
5866 rStCtrl.Seek( nOldPosCtrl );
5869 void SvxMSDffManager::SetDgContainer( SvStream& rSt )
5871 sal_uInt64 nFilePos = rSt.Tell();
5872 DffRecordHeader aDgContHd;
5873 bool bOk = ReadDffRecordHeader(rSt, aDgContHd);
5874 // insert this container only if there is also a DggAtom
5875 if (bOk && SeekToRec(rSt, DFF_msofbtDg, aDgContHd.GetRecEndFilePos()))
5877 DffRecordHeader aRecHd;
5878 if (ReadDffRecordHeader(rSt, aRecHd))
5880 sal_uInt32 nDrawingId = aRecHd.nRecInstance;
5881 maDgOffsetTable[nDrawingId] = nFilePos;
5884 rSt.Seek(nFilePos);
5887 void SvxMSDffManager::GetFidclData( sal_uInt32 nOffsDggL )
5889 if (!nOffsDggL)
5890 return;
5892 sal_uInt64 nOldPos = rStCtrl.Tell();
5894 if (nOffsDggL == rStCtrl.Seek(nOffsDggL))
5896 DffRecordHeader aRecHd;
5897 bool bOk = ReadDffRecordHeader(rStCtrl, aRecHd);
5899 DffRecordHeader aDggAtomHd;
5900 if (bOk && SeekToRec(rStCtrl, DFF_msofbtDgg, aRecHd.GetRecEndFilePos(), &aDggAtomHd))
5902 aDggAtomHd.SeekToContent( rStCtrl );
5903 sal_uInt32 nCurMaxShapeId;
5904 sal_uInt32 nDummy;
5905 rStCtrl.ReadUInt32( nCurMaxShapeId )
5906 .ReadUInt32( mnIdClusters )
5907 .ReadUInt32( nDummy )
5908 .ReadUInt32( nDummy ); // nDrawingsSaved
5910 if ( mnIdClusters-- > 2 )
5912 const std::size_t nFIDCLsize = sizeof(sal_uInt32) * 2;
5913 if ( aDggAtomHd.nRecLen == ( mnIdClusters * nFIDCLsize + 16 ) )
5915 sal_uInt64 nMaxEntriesPossible = rStCtrl.remainingSize() / nFIDCLsize;
5916 SAL_WARN_IF(nMaxEntriesPossible < mnIdClusters,
5917 "filter.ms", "FIDCL list longer than remaining bytes, ppt or parser is wrong");
5918 mnIdClusters = std::min(nMaxEntriesPossible, static_cast<sal_uInt64>(mnIdClusters));
5920 maFidcls.resize(mnIdClusters);
5921 for (sal_uInt32 i = 0; i < mnIdClusters; ++i)
5923 sal_uInt32 cspidCur; ///< number of SPIDs used so far
5924 rStCtrl.ReadUInt32( maFidcls[ i ].dgid )
5925 .ReadUInt32( cspidCur );
5931 rStCtrl.Seek( nOldPos );
5934 void SvxMSDffManager::CheckTxBxStoryChain()
5936 m_xShapeInfosById.reset(new SvxMSDffShapeInfos_ById);
5937 // mangle old Info array, sorted by nTxBxComp
5938 sal_uInt32 nChain = std::numeric_limits<sal_uInt32>::max();
5939 bool bSetReplaceFALSE = false;
5940 for (SvxMSDffShapeInfos_ByTxBxComp::iterator iter =
5941 m_xShapeInfosByTxBxComp->begin(),
5942 mark = m_xShapeInfosByTxBxComp->begin();
5943 iter != m_xShapeInfosByTxBxComp->end(); ++iter)
5945 std::shared_ptr<SvxMSDffShapeInfo> const pObj = *iter;
5946 if( pObj->nTxBxComp )
5948 // group change?
5949 // the text id also contains an internal drawing container id
5950 // to distinguish between text id of drawing objects in different
5951 // drawing containers.
5952 if( nChain != pObj->nTxBxComp )
5954 // reset mark and helper flag
5955 mark = iter;
5956 nChain = pObj->nTxBxComp;
5957 bSetReplaceFALSE = !pObj->bReplaceByFly;
5959 else if( !pObj->bReplaceByFly )
5961 // object that must NOT be replaced by frame?
5962 bSetReplaceFALSE = true;
5963 // maybe reset flags in start of group
5964 for (SvxMSDffShapeInfos_ByTxBxComp::iterator itemp = mark;
5965 itemp != iter; ++itemp)
5967 (*itemp)->bReplaceByFly = false;
5971 if( bSetReplaceFALSE )
5973 pObj->bReplaceByFly = false;
5976 // copy all Shape Info objects to m_xShapeInfosById, sorted by nShapeId
5977 pObj->nTxBxComp = pObj->nTxBxComp & 0xFFFF0000;
5978 m_xShapeInfosById->insert( pObj );
5980 // free original array but don't free its elements
5981 m_xShapeInfosByTxBxComp.reset();
5985 /*****************************************************************************
5987 Reading the Shape-Infos in the Ctor:
5988 ---------------------------------
5989 remembering the Shape-Ids and the associated Blip-Numbers and TextBox-Infos
5990 ========= ============ =============
5991 and remembering the File-Offsets for each Blip
5992 ============
5993 ******************************************************************************/
5994 void SvxMSDffManager::GetCtrlData(sal_uInt32 nOffsDggL)
5996 // position control stream
5997 if (!checkSeek(rStCtrl, nOffsDggL))
5998 return;
6000 sal_uInt8 nVer(0);
6001 sal_uInt16 nInst(0);
6002 sal_uInt16 nFbt(0);
6003 sal_uInt32 nLength(0);
6004 if( !ReadCommonRecordHeader( rStCtrl, nVer, nInst, nFbt, nLength ) ) return;
6006 sal_uInt64 nPos = nOffsDggL + DFF_COMMON_RECORD_HEADER_SIZE;
6008 // case A: first Drawing Group Container, then n times Drawing Container
6009 if( DFF_msofbtDggContainer != nFbt )
6010 return;
6012 bool bOk;
6013 GetDrawingGroupContainerData( rStCtrl, nLength );
6015 sal_uInt64 nMaxStrPos = rStCtrl.TellEnd();
6017 nPos += nLength;
6018 sal_uInt16 nDrawingContainerId = 1;
6021 if (!checkSeek(rStCtrl, nPos))
6022 break;
6024 bOk = ReadCommonRecordHeader( rStCtrl, nVer, nInst, nFbt, nLength ) && ( DFF_msofbtDgContainer == nFbt );
6026 if( !bOk )
6028 nPos++; // ????????? TODO: trying to get a one-hit wonder, this code should be rewritten...
6029 if (nPos != rStCtrl.Seek(nPos))
6030 break;
6031 bOk = ReadCommonRecordHeader( rStCtrl, nVer, nInst, nFbt, nLength )
6032 && ( DFF_msofbtDgContainer == nFbt );
6034 if( bOk )
6036 GetDrawingContainerData( rStCtrl, nLength, nDrawingContainerId );
6038 nPos += DFF_COMMON_RECORD_HEADER_SIZE + nLength;
6039 ++nDrawingContainerId;
6041 while( ( rStCtrl.GetError() == ERRCODE_NONE ) && ( nPos < nMaxStrPos ) && bOk );
6045 // from here on: Drawing Group Container i.e. document-wide valid data
6047 void SvxMSDffManager::GetDrawingGroupContainerData( SvStream& rSt, sal_uInt32 nLenDgg )
6049 sal_uInt8 nVer;
6050 sal_uInt16 nInst;
6051 sal_uInt16 nFbt;
6052 sal_uInt32 nLength;
6054 sal_uInt32 nLenBStoreCont = 0, nLenFBSE = 0;
6055 sal_uLong nRead = 0;
6057 // search for a BStore Container
6058 bool bOk = true;
6061 if (!ReadCommonRecordHeader(rSt, nVer, nInst, nFbt, nLength))
6062 return;
6063 nRead += DFF_COMMON_RECORD_HEADER_SIZE + nLength;
6064 if (DFF_msofbtBstoreContainer == nFbt)
6066 nLenBStoreCont = nLength;
6067 break;
6069 bOk = checkSeek(rSt, rSt.Tell() + nLength);
6071 while (bOk && nRead < nLenDgg);
6073 if (!bOk || !nLenBStoreCont)
6074 return;
6076 // Read all atoms of the containers from the BStore container and store all
6077 // relevant data of all contained FBSEs in out pointer array.
6078 // We also count all found FBSEs in member nBLIPCount.
6080 const sal_uLong nSkipBLIPLen = 20; // skip to get to the nBLIPLen
6081 const sal_uLong nSkipBLIPPos = 4; // thereafter skip up to nBLIPPos
6083 sal_uInt32 nBLIPLen = 0, nBLIPPos = 0;
6085 nRead = 0;
6088 if(!ReadCommonRecordHeader( rSt, nVer, nInst, nFbt, nLength)) return;
6089 nRead += DFF_COMMON_RECORD_HEADER_SIZE + nLength;
6090 if( DFF_msofbtBSE == nFbt && /* magic value from spec */ 0x2 == nVer )
6092 nLenFBSE = nLength;
6093 // is FBSE big enough for our data
6094 bOk = ( nSkipBLIPLen + 4 + nSkipBLIPPos + 4 <= nLenFBSE );
6096 if (bOk)
6098 rSt.SeekRel( nSkipBLIPLen );
6099 rSt.ReadUInt32( nBLIPLen );
6100 rSt.SeekRel( nSkipBLIPPos );
6101 rSt.ReadUInt32( nBLIPPos );
6102 bOk = rSt.GetError() == ERRCODE_NONE;
6104 nLength -= nSkipBLIPLen+ 4 + nSkipBLIPPos + 4;
6107 if (bOk)
6109 // specialty:
6110 // If nBLIPLen is less than nLenFBSE AND nBLIPPos is NULL,
6111 // then we assume, that the image is in FBSE!
6112 if( (!nBLIPPos) && (nBLIPLen < nLenFBSE) )
6113 nBLIPPos = rSt.Tell() + 4;
6115 if( USHRT_MAX == nBLIPCount )
6116 nBLIPCount = 1;
6117 else
6118 nBLIPCount++;
6120 // now save the info for later access
6121 m_pBLIPInfos->push_back(SvxMSDffBLIPInfo(nBLIPPos));
6123 if (!checkSeek(rSt, rSt.Tell() + nLength))
6124 return; // invalid offset
6126 else return; // invalid input
6128 while( nRead < nLenBStoreCont );
6132 // from now on: Drawing Container which means Pages (Sheet, Slide) - wide valid data
6133 // ================= ======
6135 void SvxMSDffManager::GetDrawingContainerData( SvStream& rSt, sal_uInt32 nLenDg,
6136 sal_uInt16 nDrawingContainerId )
6138 sal_uInt8 nVer;sal_uInt16 nInst;sal_uInt16 nFbt;sal_uInt32 nLength;
6140 sal_uLong nReadDg = 0;
6142 // We are now in a drawing container (one per each page) and
6143 // we now have to iterate through all contained shape group containers
6146 if (!ReadCommonRecordHeader(rSt, nVer, nInst, nFbt, nLength))
6147 return;
6148 nReadDg += DFF_COMMON_RECORD_HEADER_SIZE;
6149 // Patriarch found (the upmost shape group container) ?
6150 if (DFF_msofbtSpgrContainer == nFbt)
6152 if (!GetShapeGroupContainerData(rSt, nLength, true, nDrawingContainerId))
6153 return;
6155 // empty Shape Container ? (outside of shape group container)
6156 else if (DFF_msofbtSpContainer == nFbt)
6158 if (!GetShapeContainerData(
6159 rSt, nLength, std::numeric_limits<sal_uInt64>::max(), nDrawingContainerId))
6160 return;
6162 else
6164 if (!checkSeek(rSt, rSt.Tell() + nLength))
6165 return;
6167 nReadDg += nLength;
6169 while( nReadDg < nLenDg );
6172 bool SvxMSDffManager::GetShapeGroupContainerData( SvStream& rSt,
6173 sal_uInt32 nLenShapeGroupCont,
6174 bool bPatriarch,
6175 sal_uInt16 nDrawingContainerId )
6177 sal_uInt8 nVer;sal_uInt16 nInst;sal_uInt16 nFbt;sal_uInt32 nLength;
6178 sal_uInt64 nStartShapeGroupCont = rSt.Tell();
6179 // We are now in a shape group container (conditionally multiple per page)
6180 // and we now have to iterate through all contained shape containers
6181 bool bFirst = !bPatriarch;
6182 sal_uLong nReadSpGrCont = 0;
6185 if( !ReadCommonRecordHeader( rSt, nVer, nInst, nFbt, nLength ) )
6186 return false;
6187 nReadSpGrCont += DFF_COMMON_RECORD_HEADER_SIZE;
6188 // Shape Container?
6189 if( DFF_msofbtSpContainer == nFbt )
6191 sal_uInt64 nGroupOffs = bFirst ? nStartShapeGroupCont - DFF_COMMON_RECORD_HEADER_SIZE : std::numeric_limits<sal_uInt64>::max();
6192 if ( !GetShapeContainerData( rSt, nLength, nGroupOffs, nDrawingContainerId ) )
6193 return false;
6194 bFirst = false;
6196 // nested shape group container ?
6197 else if( DFF_msofbtSpgrContainer == nFbt )
6199 if ( !GetShapeGroupContainerData( rSt, nLength, false, nDrawingContainerId ) )
6200 return false;
6202 else
6204 if (!checkSeek(rSt, rSt.Tell() + nLength))
6205 return false;
6207 nReadSpGrCont += nLength;
6209 while( nReadSpGrCont < nLenShapeGroupCont );
6210 // position the stream correctly
6211 rSt.Seek( nStartShapeGroupCont + nLenShapeGroupCont );
6212 return true;
6215 bool SvxMSDffManager::GetShapeContainerData( SvStream& rSt,
6216 sal_uInt32 nLenShapeCont,
6217 sal_uInt64 nPosGroup,
6218 sal_uInt16 nDrawingContainerId )
6220 sal_uInt8 nVer;sal_uInt16 nInst;sal_uInt16 nFbt;sal_uInt32 nLength;
6221 sal_uInt64 nStartShapeCont = rSt.Tell();
6223 // We are in a shape container (possibly more than one per shape group) and we now
6224 // have to fetch the shape id and file position (to be able to access them again later)
6225 // and the first BStore reference (if present).
6226 sal_uInt32 nLenShapePropTbl = 0;
6227 sal_uLong nReadSpCont = 0;
6229 // Store file offset of the shape containers or respectively the group(!).
6230 sal_uInt64 nStartOffs = (std::numeric_limits<sal_uInt64>::max() > nPosGroup) ?
6231 nPosGroup : nStartShapeCont - DFF_COMMON_RECORD_HEADER_SIZE;
6232 SvxMSDffShapeInfo aInfo( nStartOffs );
6234 // Can the shape be replaced with a frame?
6235 // (provided that it is a TextBox and the text is not rotated)
6236 bool bCanBeReplaced = nPosGroup >= std::numeric_limits<sal_uInt64>::max();
6238 // we don't know yet whether it's a TextBox
6239 MSO_SPT eShapeType = mso_sptNil;
6241 // analyze Shape
6245 if(!ReadCommonRecordHeader( rSt, nVer, nInst, nFbt, nLength)) return false;
6246 nReadSpCont += DFF_COMMON_RECORD_HEADER_SIZE;
6247 // FSP ?
6248 if( ( DFF_msofbtSp == nFbt ) && ( 4 <= nLength ) )
6250 // we've found the FSP: note Shape Type and Id!
6251 eShapeType = static_cast<MSO_SPT>(nInst);
6252 rSt.ReadUInt32( aInfo.nShapeId );
6253 rSt.SeekRel( nLength - 4 );
6254 nReadSpCont += nLength;
6256 else if( DFF_msofbtOPT == nFbt ) // Shape Property Table ?
6258 // We've found the Property Table:
6259 // search for the Blip Property!
6260 sal_uLong nPropRead = 0;
6261 nLenShapePropTbl = nLength;
6262 auto nStartShapePropTbl = rSt.Tell();
6265 sal_uInt16 nPropId(0);
6266 sal_uInt32 nPropVal(0);
6268 rSt.ReadUInt16( nPropId )
6269 .ReadUInt32( nPropVal );
6270 nPropRead += 6;
6272 switch( nPropId )
6274 case DFF_Prop_txflTextFlow :
6275 //Writer can now handle vertical textflows in its
6276 //native frames, to only need to do this for the
6277 //other two formats
6279 //Writer will handle all textflow except BtoT
6280 if (GetSvxMSDffSettings() &
6281 (SVXMSDFF_SETTINGS_IMPORT_PPT |
6282 SVXMSDFF_SETTINGS_IMPORT_EXCEL))
6284 if( 0 != nPropVal )
6285 bCanBeReplaced = false;
6287 else if (
6288 (nPropVal != mso_txflHorzN) &&
6289 (nPropVal != mso_txflTtoBA)
6292 bCanBeReplaced = false;
6294 break;
6295 case DFF_Prop_cdirFont :
6296 //Writer can now handle right to left and left
6297 //to right in its native frames, so only do
6298 //this for the other two formats.
6299 if (GetSvxMSDffSettings() &
6300 (SVXMSDFF_SETTINGS_IMPORT_PPT |
6301 SVXMSDFF_SETTINGS_IMPORT_EXCEL))
6303 if( 0 != nPropVal )
6304 bCanBeReplaced = false;
6306 break;
6307 case DFF_Prop_Rotation :
6308 if( 0 != nPropVal )
6309 bCanBeReplaced = false;
6310 break;
6312 case DFF_Prop_gtextFStrikethrough :
6313 if( ( 0x20002000 & nPropVal ) == 0x20002000 )
6314 bCanBeReplaced = false;
6315 break;
6317 case DFF_Prop_fc3DLightFace :
6318 if( ( 0x00080008 & nPropVal ) == 0x00080008 )
6319 bCanBeReplaced = false;
6320 break;
6322 case DFF_Prop_WrapText :
6323 //TODO: eWrapMode = (MSO_WrapMode)nPropVal;
6324 break;
6326 default:
6328 // is the Bit set and valid?
6329 if( 0x4000 == ( nPropId & 0xC000 ) )
6331 // Blip Property found: remember BStore Idx!
6332 nPropRead = nLenShapePropTbl;
6334 else if( 0x8000 & nPropId )
6336 // complex Prop found:
6337 // Length is always 6. The length of the appended extra data
6338 // after the actual prop table is of different size.
6341 break;
6344 while (rSt.good() && nPropRead < nLenShapePropTbl);
6345 rSt.Seek( nStartShapePropTbl + nLenShapePropTbl );
6346 nReadSpCont += nLenShapePropTbl;
6348 else if( ( DFF_msofbtClientTextbox == nFbt ) && ( 4 == nLength ) ) // Text-Box-Story-Entry found
6350 rSt.ReadUInt32( aInfo.nTxBxComp );
6351 // Add internal drawing container id to text id.
6352 // Note: The text id uses the first two bytes, while the internal
6353 // drawing container id used the second two bytes.
6354 aInfo.nTxBxComp = ( aInfo.nTxBxComp & 0xFFFF0000 ) +
6355 nDrawingContainerId;
6356 DBG_ASSERT( (aInfo.nTxBxComp & 0x0000FFFF) == nDrawingContainerId,
6357 "<SvxMSDffManager::GetShapeContainerData(..)> - internal drawing container Id could not be correctly merged into DFF_msofbtClientTextbox value." );
6359 else
6361 if (!checkSeek(rSt, rSt.Tell() + nLength))
6363 SAL_WARN("filter.ms", "remaining record longer than available data, ppt or parser is wrong");
6364 break;
6366 nReadSpCont += nLength;
6369 while( nReadSpCont < nLenShapeCont );
6372 // Now possibly store the information for subsequent accesses to the shape
6374 if( aInfo.nShapeId )
6376 // Possibly allow replacement of textboxes with frames
6377 if( bCanBeReplaced
6378 && aInfo.nTxBxComp
6379 && (
6380 ( eShapeType == mso_sptTextSimple )
6381 || ( eShapeType == mso_sptTextBox )
6382 || ( eShapeType == mso_sptRectangle )
6383 || ( eShapeType == mso_sptRoundRectangle )
6386 aInfo.bReplaceByFly = true;
6388 m_xShapeInfosByTxBxComp->insert(std::make_shared<SvxMSDffShapeInfo>(
6389 aInfo));
6390 m_aShapeOrders.push_back(std::make_unique<SvxMSDffShapeOrder>(
6391 aInfo.nShapeId ));
6394 // and position the Stream correctly again
6395 rSt.Seek( nStartShapeCont + nLenShapeCont );
6396 return true;
6400 /*****************************************************************************
6402 Access to a shape at runtime (via the Shape-Id)
6403 ----------------------------
6404 ******************************************************************************/
6405 bool SvxMSDffManager::GetShape(sal_uLong nId, rtl::Reference<SdrObject>& rpShape,
6406 SvxMSDffImportData& rData)
6408 auto const pTmpRec = std::make_shared<SvxMSDffShapeInfo>(0, nId);
6410 SvxMSDffShapeInfos_ById::const_iterator const it =
6411 m_xShapeInfosById->find(pTmpRec);
6412 if (it == m_xShapeInfosById->end())
6413 return false;
6415 // Possibly delete old error flag.
6416 if( rStCtrl.GetError() )
6417 rStCtrl.ResetError();
6418 // store FilePos of the stream(s)
6419 sal_uInt64 nOldPosCtrl = rStCtrl.Tell();
6420 sal_uInt64 nOldPosData = pStData ? pStData->Tell() : nOldPosCtrl;
6421 // jump to the shape in the control stream
6422 sal_uInt64 const nFilePos((*it)->nFilePos);
6423 bool bSeeked = (nFilePos == rStCtrl.Seek(nFilePos));
6425 // if it failed, reset error statusF
6426 if (!bSeeked || rStCtrl.GetError())
6427 rStCtrl.ResetError();
6428 else
6429 rpShape = ImportObj( rStCtrl, rData, rData.aParentRect, rData.aParentRect, /*nCalledByGroup*/0, /*pShapeId*/nullptr );
6431 // restore old FilePos of the stream(s)
6432 rStCtrl.Seek( nOldPosCtrl );
6433 if( &rStCtrl != pStData && pStData )
6434 pStData->Seek( nOldPosData );
6435 return bool( rpShape );
6439 /** Access to a BLIP at runtime (if the Blip-Number is already known)
6441 bool SvxMSDffManager::GetBLIP( sal_uLong nIdx_, Graphic& rGraphic, tools::Rectangle* pVisArea )
6443 if (!pStData)
6444 return false;
6446 bool bOk = false; // initialize result variable
6448 // check if a graphic for this blipId is already imported
6449 if (nIdx_)
6451 auto iter = aEscherBlipCache.find(nIdx_);
6453 if (iter != aEscherBlipCache.end())
6455 /* if this entry is available */
6456 rGraphic = iter->second;
6457 if (rGraphic.GetType() != GraphicType::NONE)
6458 bOk = true;
6459 else
6460 aEscherBlipCache.erase(iter);
6464 if (!bOk)
6466 sal_uInt16 nIdx = sal_uInt16( nIdx_ );
6467 if (!nIdx || (m_pBLIPInfos->size() < nIdx))
6468 return false;
6470 // possibly delete old error flag(s)
6471 if( rStCtrl.GetError() )
6472 rStCtrl.ResetError();
6473 if( ( &rStCtrl != pStData )
6474 && pStData->GetError() )
6475 pStData->ResetError();
6477 // remember FilePos of the stream(s)
6478 sal_uInt64 nOldPosCtrl = rStCtrl.Tell();
6479 sal_uInt64 nOldPosData = pStData->Tell();
6481 // fetch matching info struct out of the pointer array
6482 SvxMSDffBLIPInfo& rInfo = (*m_pBLIPInfos)[ nIdx-1 ];
6483 // jump to the BLIP atom in the data stream
6484 bOk = checkSeek(*pStData, rInfo.nFilePos);
6485 // possibly reset error status
6486 if (!bOk || pStData->GetError())
6487 pStData->ResetError();
6488 else
6489 bOk = GetBLIPDirect( *pStData, rGraphic, pVisArea );
6490 if( pStData2 && !bOk )
6492 // Error, but the is a second chance: There is a second
6493 // data stream in which the graphic could be stored!
6494 if( pStData2->GetError() )
6495 pStData2->ResetError();
6496 sal_uInt64 nOldPosData2 = pStData2->Tell();
6497 // jump to the BLIP atom in the second data stream
6498 bOk = checkSeek(*pStData2, rInfo.nFilePos);
6499 // reset error status if necessary
6500 if (!bOk || pStData2->GetError())
6501 pStData2->ResetError();
6502 else
6503 bOk = GetBLIPDirect( *pStData2, rGraphic, pVisArea );
6504 // restore of FilePos of the second data stream
6505 pStData2->Seek( nOldPosData2 );
6507 // restore old FilePos of the stream(s)
6508 rStCtrl.Seek( nOldPosCtrl );
6509 if( &rStCtrl != pStData )
6510 pStData->Seek( nOldPosData );
6512 if (bOk)
6514 // create new BlipCacheEntry for this graphic
6515 aEscherBlipCache.insert(std::make_pair(nIdx_, rGraphic));
6519 return bOk;
6522 /* access to a BLIP at runtime (with correctly positioned stream)
6523 ---------------------------------
6524 ******************************************************************************/
6525 bool SvxMSDffManager::GetBLIPDirect( SvStream& rBLIPStream, Graphic& rData, tools::Rectangle* pVisArea )
6527 sal_uInt64 nOldPos = rBLIPStream.Tell();
6529 ErrCode nRes = ERRCODE_GRFILTER_OPENERROR; // initialize error variable
6531 // check whether it's really a BLIP
6532 sal_uInt32 nLength;
6533 sal_uInt16 nInst, nFbt( 0 );
6534 sal_uInt8 nVer;
6535 if( ReadCommonRecordHeader( rBLIPStream, nVer, nInst, nFbt, nLength) && ( 0xF018 <= nFbt ) && ( 0xF117 >= nFbt ) )
6537 Size aMtfSize100;
6538 bool bMtfBLIP = false;
6539 bool bZCodecCompression = false;
6540 // now position it exactly at the beginning of the embedded graphic
6541 sal_uLong nSkip = (nInst & 0x0001) ? 32 : 16;
6542 const OfficeArtBlipRecInstance aRecInstanse = OfficeArtBlipRecInstance(nInst & 0xFFFE);
6543 switch (aRecInstanse)
6545 case OfficeArtBlipRecInstance::EMF:
6546 case OfficeArtBlipRecInstance::WMF:
6547 case OfficeArtBlipRecInstance::PICT:
6549 rBLIPStream.SeekRel(nSkip + 20);
6551 // read in size of metafile in English Metric Units (EMUs)
6552 sal_Int32 width(0), height(0);
6553 rBLIPStream.ReadInt32(width).ReadInt32(height);
6554 aMtfSize100.setWidth(width);
6555 aMtfSize100.setHeight(height);
6557 // 1 EMU = 1/360,000 of a centimeter
6558 // scale to 1/100mm
6559 aMtfSize100.setWidth(aMtfSize100.Width() / 360);
6560 aMtfSize100.setHeight(aMtfSize100.Height() / 360);
6562 if (pVisArea) // seem that we currently are skipping the visarea position
6563 *pVisArea = tools::Rectangle(Point(), aMtfSize100);
6565 // skip rest of header
6566 nSkip = 6;
6567 bMtfBLIP = bZCodecCompression = true;
6569 break;
6570 case OfficeArtBlipRecInstance::JPEG_RGB:
6571 case OfficeArtBlipRecInstance::JPEG_CMYK:
6572 case OfficeArtBlipRecInstance::PNG:
6573 case OfficeArtBlipRecInstance::DIB:
6574 case OfficeArtBlipRecInstance::TIFF:
6575 nSkip += 1; // Skip one byte tag
6576 break;
6578 rBLIPStream.SeekRel( nSkip );
6580 SvStream* pGrStream = &rBLIPStream;
6581 std::unique_ptr<SvMemoryStream> xOut;
6582 if( bZCodecCompression )
6584 xOut.reset(new SvMemoryStream( 0x8000, 0x4000 ));
6585 ZCodec aZCodec( 0x8000, 0x8000 );
6586 aZCodec.BeginCompression();
6587 aZCodec.Decompress( rBLIPStream, *xOut );
6588 aZCodec.EndCompression();
6589 xOut->Seek( STREAM_SEEK_TO_BEGIN );
6590 xOut->SetResizeOffset( 0 ); // sj: #i102257# setting ResizeOffset of 0 prevents from seeking
6591 // behind the stream end (allocating too much memory)
6592 pGrStream = xOut.get();
6595 #ifdef DEBUG_FILTER_MSDFFIMP
6596 // extract graphics from ole storage into "dbggfxNNN.*"
6597 static sal_Int32 nGrfCount;
6599 OUString aFileName = "dbggfx" + OUString::number(nGrfCount++);
6600 switch (aRecInstanse)
6602 case OfficeArtBlipRecInstance::WMF:
6603 aFileName += ".wmf";
6604 break;
6605 case OfficeArtBlipRecInstance::EMF:
6606 aFileName += ".emf";
6607 break;
6608 case OfficeArtBlipRecInstance::PICT:
6609 aFileName += ".pct";
6610 break;
6611 case OfficeArtBlipRecInstance::JPEG_RGB:
6612 case OfficeArtBlipRecInstance::JPEG_CMYK:
6613 aFileName += ".jpg";
6614 break;
6615 case OfficeArtBlipRecInstance::PNG:
6616 aFileName += ".png";
6617 break;
6618 case OfficeArtBlipRecInstance::DIB:
6619 aFileName += ".bmp";
6620 break;
6621 case OfficeArtBlipRecInstance::TIFF:
6622 aFileName += ".tif";
6623 break;
6627 OUString aURLStr;
6628 if( osl::FileBase::getFileURLFromSystemPath( Application::GetAppFileName(), aURLStr ) == osl::FileBase::E_None )
6630 INetURLObject aURL( aURLStr );
6632 aURL.removeSegment();
6633 aURL.removeFinalSlash();
6634 aURL.Append( aFileName );
6636 aURLStr = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
6638 SAL_INFO("filter.ms", "dumping " << aURLStr);
6640 std::unique_ptr<SvStream> pDbgOut(::utl::UcbStreamHelper::CreateStream(aURLStr, StreamMode::TRUNC | StreamMode::WRITE));
6642 if( pDbgOut )
6644 if ( bZCodecCompression )
6646 pDbgOut->WriteBytes(xOut->GetData(), xOut->TellEnd());
6647 xOut->Seek(STREAM_SEEK_TO_BEGIN);
6649 else
6651 sal_Int32 nDbgLen = nLength - nSkip;
6652 if ( nDbgLen )
6654 std::vector<char> aData(nDbgLen);
6655 pGrStream->ReadBytes(aData.data(), nDbgLen);
6656 pDbgOut->WriteBytes(aData.data(), nDbgLen);
6657 pGrStream->SeekRel(-nDbgLen);
6662 #endif
6663 if (aRecInstanse == OfficeArtBlipRecInstance::DIB)
6664 { // getting the DIBs immediately
6665 Bitmap aNew;
6666 if( ReadDIB(aNew, *pGrStream, false) )
6668 rData = Graphic(BitmapEx(aNew));
6669 nRes = ERRCODE_NONE;
6672 else
6673 { // and unleash our filter
6674 GraphicFilter& rGF = GraphicFilter::GetGraphicFilter();
6675 // ImportUnloadedGraphic() may simply read the entire rest of the stream,
6676 // which may be very large if the whole document is large. Limit the read
6677 // size to the size of this record.
6678 sal_uInt64 maxSize = pGrStream == &rBLIPStream ? nLength : 0;
6679 Graphic aGraphic;
6681 // Size available in metafile header.
6682 if (aMtfSize100.getWidth() && aMtfSize100.getHeight())
6683 aGraphic = rGF.ImportUnloadedGraphic(*pGrStream, maxSize, &aMtfSize100);
6684 else
6685 aGraphic = rGF.ImportUnloadedGraphic(*pGrStream, maxSize);
6687 if (!aGraphic.IsNone())
6689 rData = aGraphic;
6690 nRes = ERRCODE_NONE;
6692 else
6693 nRes = rGF.ImportGraphic( rData, u"", *pGrStream );
6695 // SJ: I40472, sometimes the aspect ratio (aMtfSize100) does not match and we get scaling problems,
6696 // then it is better to use the prefsize that is stored within the metafile. Bug #72846# for what the
6697 // scaling has been implemented does not happen anymore.
6699 // For pict graphics we will furthermore scale the metafile, because font scaling leads to error if the
6700 // dxarray is empty (this has been solved in wmf/emf but not for pict)
6701 if (bMtfBLIP && (ERRCODE_NONE == nRes) && (rData.GetType() == GraphicType::GdiMetafile)
6702 && (aRecInstanse == OfficeArtBlipRecInstance::PICT))
6704 if ( ( aMtfSize100.Width() >= 1000 ) && ( aMtfSize100.Height() >= 1000 ) )
6705 { // #75956#, scaling does not work properly, if the graphic is less than 1cm
6706 GDIMetaFile aMtf( rData.GetGDIMetaFile() );
6707 const Size aOldSize( aMtf.GetPrefSize() );
6709 if( aOldSize.Width() && ( aOldSize.Width() != aMtfSize100.Width() ) &&
6710 aOldSize.Height() && ( aOldSize.Height() != aMtfSize100.Height() ) )
6712 aMtf.Scale( static_cast<double>(aMtfSize100.Width()) / aOldSize.Width(),
6713 static_cast<double>(aMtfSize100.Height()) / aOldSize.Height() );
6714 aMtf.SetPrefSize( aMtfSize100 );
6715 aMtf.SetPrefMapMode(MapMode(MapUnit::Map100thMM));
6716 rData = aMtf;
6721 // reset error status if necessary
6722 if ( ERRCODE_IO_PENDING == pGrStream->GetError() )
6723 pGrStream->ResetError();
6725 rBLIPStream.Seek( nOldPos ); // restore old FilePos of the stream
6727 return ( ERRCODE_NONE == nRes ); // return result
6730 /* also static */
6731 bool SvxMSDffManager::ReadCommonRecordHeader(SvStream& rSt,
6732 sal_uInt8& rVer, sal_uInt16& rInst, sal_uInt16& rFbt, sal_uInt32& rLength)
6734 sal_uInt16 nTmp(0);
6735 rSt.ReadUInt16( nTmp ).ReadUInt16( rFbt ).ReadUInt32( rLength );
6736 rVer = sal::static_int_cast< sal_uInt8 >(nTmp & 15);
6737 rInst = nTmp >> 4;
6738 if (!rSt.good())
6739 return false;
6740 if (rLength > nMaxLegalDffRecordLength)
6741 return false;
6742 return true;
6745 void SvxMSDffManager::ProcessClientAnchor(SvStream& rStData, sal_uInt32 nDatLen,
6746 std::unique_ptr<char[]>& rpBuff, sal_uInt32& rBuffLen )
6748 if( nDatLen )
6750 rBuffLen = std::min(rStData.remainingSize(), static_cast<sal_uInt64>(nDatLen));
6751 rpBuff.reset( new char[rBuffLen] );
6752 rBuffLen = rStData.ReadBytes(rpBuff.get(), rBuffLen);
6756 void SvxMSDffManager::ProcessClientData(SvStream& rStData, sal_uInt32 nDatLen,
6757 std::unique_ptr<char[]>& rpBuff, sal_uInt32& rBuffLen )
6759 if( nDatLen )
6761 rBuffLen = std::min(rStData.remainingSize(), static_cast<sal_uInt64>(nDatLen));
6762 rpBuff.reset( new char[rBuffLen] );
6763 rBuffLen = rStData.ReadBytes(rpBuff.get(), rBuffLen);
6768 void SvxMSDffManager::ProcessClientAnchor2( SvStream& /* rSt */, DffRecordHeader& /* rHd */ , DffObjData& /* rObj */ )
6770 // will be overridden by SJ in Draw
6773 bool SvxMSDffManager::GetOLEStorageName( sal_uInt32, OUString&, tools::SvRef<SotStorage>&, uno::Reference < embed::XStorage >& ) const
6775 return false;
6778 bool SvxMSDffManager::ShapeHasText( sal_uLong /* nShapeId */, sal_uLong /* nFilePos */ ) const
6780 return true;
6783 // #i32596# - add new parameter <_nCalledByGroup>
6784 rtl::Reference<SdrObject> SvxMSDffManager::ImportOLE( sal_uInt32 nOLEId,
6785 const Graphic& rGrf,
6786 const tools::Rectangle& rBoundRect,
6787 const tools::Rectangle& rVisArea,
6788 const int /* _nCalledByGroup */ ) const
6790 rtl::Reference<SdrObject> pRet;
6791 OUString sStorageName;
6792 tools::SvRef<SotStorage> xSrcStg;
6793 ErrCode nError = ERRCODE_NONE;
6794 uno::Reference < embed::XStorage > xDstStg;
6795 if( GetOLEStorageName( nOLEId, sStorageName, xSrcStg, xDstStg ))
6796 pRet = CreateSdrOLEFromStorage(
6797 *GetModel(),
6798 sStorageName,
6799 xSrcStg,
6800 xDstStg,
6801 rGrf,
6802 rBoundRect,
6803 rVisArea,
6804 pStData,
6805 nError,
6806 nSvxMSDffOLEConvFlags,
6807 embed::Aspects::MSOLE_CONTENT,
6808 maBaseURL);
6809 return pRet;
6812 bool SvxMSDffManager::MakeContentStream( SotStorage * pStor, const GDIMetaFile & rMtf )
6814 tools::SvRef<SotStorageStream> xStm = pStor->OpenSotStream(SVEXT_PERSIST_STREAM);
6815 xStm->SetVersion( pStor->GetVersion() );
6816 xStm->SetBufferSize( 8192 );
6818 Impl_OlePres aEle;
6819 // Convert the size in 1/100 mm
6820 // If a not applicable MapUnit (device dependent) is used,
6821 // SV tries to guess a best match for the right value
6822 Size aSize = rMtf.GetPrefSize();
6823 const MapMode& aMMSrc = rMtf.GetPrefMapMode();
6824 MapMode aMMDst( MapUnit::Map100thMM );
6825 aSize = OutputDevice::LogicToLogic( aSize, aMMSrc, aMMDst );
6826 aEle.SetSize( aSize );
6827 aEle.SetAspect( ASPECT_CONTENT );
6828 aEle.SetAdviseFlags( 2 );
6829 aEle.SetMtf( rMtf );
6830 aEle.Write( *xStm );
6832 xStm->SetBufferSize( 0 );
6833 return xStm->GetError() == ERRCODE_NONE;
6836 namespace {
6838 struct ClsIDs {
6839 sal_uInt32 nId;
6840 const char* pSvrName;
6841 const char* pDspName;
6846 const ClsIDs aClsIDs[] = {
6848 { 0x000212F0, "MSWordArt", "Microsoft Word Art" },
6849 { 0x000212F0, "MSWordArt.2", "Microsoft Word Art 2.0" },
6851 // MS Apps
6852 { 0x00030000, "ExcelWorksheet", "Microsoft Excel Worksheet" },
6853 { 0x00030001, "ExcelChart", "Microsoft Excel Chart" },
6854 { 0x00030002, "ExcelMacrosheet", "Microsoft Excel Macro" },
6855 { 0x00030003, "WordDocument", "Microsoft Word Document" },
6856 { 0x00030004, "MSPowerPoint", "Microsoft PowerPoint" },
6857 { 0x00030005, "MSPowerPointSho", "Microsoft PowerPoint Slide Show"},
6858 { 0x00030006, "MSGraph", "Microsoft Graph" },
6859 { 0x00030007, "MSDraw", "Microsoft Draw" },
6860 { 0x00030008, "Note-It", "Microsoft Note-It" },
6861 { 0x00030009, "WordArt", "Microsoft Word Art" },
6862 { 0x0003000a, "PBrush", "Microsoft PaintBrush Picture" },
6863 { 0x0003000b, "Equation", "Microsoft Equation Editor" },
6864 { 0x0003000c, "Package", "Package" },
6865 { 0x0003000d, "SoundRec", "Sound" },
6866 { 0x0003000e, "MPlayer", "Media Player" },
6867 // MS Demos
6868 { 0x0003000f, "ServerDemo", "OLE 1.0 Server Demo" },
6869 { 0x00030010, "Srtest", "OLE 1.0 Test Demo" },
6870 { 0x00030011, "SrtInv", "OLE 1.0 Inv Demo" },
6871 { 0x00030012, "OleDemo", "OLE 1.0 Demo" },
6873 // Coromandel / Dorai Swamy / 718-793-7963
6874 { 0x00030013, "CoromandelIntegra", "Coromandel Integra" },
6875 { 0x00030014, "CoromandelObjServer","Coromandel Object Server" },
6877 // 3-d Visions Corp / Peter Hirsch / 310-325-1339
6878 { 0x00030015, "StanfordGraphics", "Stanford Graphics" },
6880 // Deltapoint / Nigel Hearne / 408-648-4000
6881 { 0x00030016, "DGraphCHART", "DeltaPoint Graph Chart" },
6882 { 0x00030017, "DGraphDATA", "DeltaPoint Graph Data" },
6884 // Corel / Richard V. Woodend / 613-728-8200 x1153
6885 { 0x00030018, "PhotoPaint", "Corel PhotoPaint" },
6886 { 0x00030019, "CShow", "Corel Show" },
6887 { 0x0003001a, "CorelChart", "Corel Chart" },
6888 { 0x0003001b, "CDraw", "Corel Draw" },
6890 // Inset Systems / Mark Skiba / 203-740-2400
6891 { 0x0003001c, "HJWIN1.0", "Inset Systems" },
6893 // Mark V Systems / Mark McGraw / 818-995-7671
6894 { 0x0003001d, "ObjMakerOLE", "MarkV Systems Object Maker" },
6896 // IdentiTech / Mike Gilger / 407-951-9503
6897 { 0x0003001e, "FYI", "IdentiTech FYI" },
6898 { 0x0003001f, "FYIView", "IdentiTech FYI Viewer" },
6900 // Inventa Corporation / Balaji Varadarajan / 408-987-0220
6901 { 0x00030020, "Stickynote", "Inventa Sticky Note" },
6903 // ShapeWare Corp. / Lori Pearce / 206-467-6723
6904 { 0x00030021, "ShapewareVISIO10", "Shapeware Visio 1.0" },
6905 { 0x00030022, "ImportServer", "Spaheware Import Server" },
6907 // test app SrTest
6908 { 0x00030023, "SrvrTest", "OLE 1.0 Server Test" },
6910 // test app ClTest. Doesn't really work as a server but is in reg db
6911 { 0x00030025, "Cltest", "OLE 1.0 Client Test" },
6913 // Microsoft ClipArt Gallery Sherry Larsen-Holmes
6914 { 0x00030026, "MS_ClipArt_Gallery", "Microsoft ClipArt Gallery" },
6915 // Microsoft Project Cory Reina
6916 { 0x00030027, "MSProject", "Microsoft Project" },
6918 // Microsoft Works Chart
6919 { 0x00030028, "MSWorksChart", "Microsoft Works Chart" },
6921 // Microsoft Works Spreadsheet
6922 { 0x00030029, "MSWorksSpreadsheet", "Microsoft Works Spreadsheet" },
6924 // AFX apps - Dean McCrory
6925 { 0x0003002A, "MinSvr", "AFX Mini Server" },
6926 { 0x0003002B, "HierarchyList", "AFX Hierarchy List" },
6927 { 0x0003002C, "BibRef", "AFX BibRef" },
6928 { 0x0003002D, "MinSvrMI", "AFX Mini Server MI" },
6929 { 0x0003002E, "TestServ", "AFX Test Server" },
6931 // Ami Pro
6932 { 0x0003002F, "AmiProDocument", "Ami Pro Document" },
6934 // WordPerfect Presentations For Windows
6935 { 0x00030030, "WPGraphics", "WordPerfect Presentation" },
6936 { 0x00030031, "WPCharts", "WordPerfect Chart" },
6938 // MicroGrafx Charisma
6939 { 0x00030032, "Charisma", "MicroGrafx Charisma" },
6940 { 0x00030033, "Charisma_30", "MicroGrafx Charisma 3.0" },
6941 { 0x00030034, "CharPres_30", "MicroGrafx Charisma 3.0 Pres" },
6942 // MicroGrafx Draw
6943 { 0x00030035, "Draw", "MicroGrafx Draw" },
6944 // MicroGrafx Designer
6945 { 0x00030036, "Designer_40", "MicroGrafx Designer 4.0" },
6947 // STAR DIVISION
6948 { 0x00043AD2, "FontWork", "Star FontWork" },
6950 { 0, "", "" } };
6953 bool SvxMSDffManager::ConvertToOle2( SvStream& rStm, sal_uInt32 nReadLen,
6954 const GDIMetaFile * pMtf, const tools::SvRef<SotStorage>& rDest )
6956 bool bMtfRead = false;
6957 tools::SvRef<SotStorageStream> xOle10Stm = rDest->OpenSotStream( "\1Ole10Native",
6958 StreamMode::WRITE| StreamMode::SHARE_DENYALL );
6959 if( xOle10Stm->GetError() )
6960 return false;
6962 OUString aSvrName;
6963 sal_uInt32 nDummy0;
6964 sal_uInt32 nDummy1;
6965 sal_uInt32 nBytesRead = 0;
6968 sal_uInt32 nType(0);
6969 sal_uInt32 nRecType(0);
6970 sal_uInt32 nStrLen(0);
6972 rStm.ReadUInt32( nType );
6973 rStm.ReadUInt32( nRecType );
6974 rStm.ReadUInt32( nStrLen );
6975 if( nStrLen )
6977 if( 0x10000L > nStrLen )
6979 std::unique_ptr<char[]> pBuf(new char[ nStrLen ]);
6980 rStm.ReadBytes(pBuf.get(), nStrLen);
6981 aSvrName = OUString( pBuf.get(), static_cast<sal_uInt16>(nStrLen)-1, osl_getThreadTextEncoding() );
6983 else
6984 break;
6986 rStm.ReadUInt32( nDummy0 );
6987 rStm.ReadUInt32( nDummy1 );
6988 sal_uInt32 nDataLen(0);
6989 rStm.ReadUInt32( nDataLen );
6991 nBytesRead += 6 * sizeof( sal_uInt32 ) + nStrLen + nDataLen;
6993 if (rStm.good() && nReadLen > nBytesRead && nDataLen)
6995 if( xOle10Stm.is() )
6997 std::unique_ptr<sal_uInt8[]> pData(new sal_uInt8[ nDataLen ]);
6998 rStm.ReadBytes(pData.get(), nDataLen);
7000 // write to ole10 stream
7001 xOle10Stm->WriteUInt32( nDataLen );
7002 xOle10Stm->WriteBytes(pData.get(), nDataLen);
7003 xOle10Stm = tools::SvRef<SotStorageStream>();
7005 // set the compobj stream
7006 const ClsIDs* pIds;
7007 for( pIds = aClsIDs; pIds->nId; pIds++ )
7009 if( aSvrName == OUString::createFromAscii(pIds->pSvrName) )
7010 break;
7013 if( pIds->nId )
7015 // found!
7016 SotClipboardFormatId nCbFmt = SotExchange::RegisterFormatName( aSvrName );
7017 rDest->SetClass( SvGlobalName( pIds->nId, 0, 0, 0xc0,0,0,0,0,0,0,0x46 ), nCbFmt,
7018 OUString::createFromAscii( pIds->pDspName ) );
7020 else
7022 SotClipboardFormatId nCbFmt = SotExchange::RegisterFormatName( aSvrName );
7023 rDest->SetClass( SvGlobalName(), nCbFmt, aSvrName );
7026 else if( nRecType == 5 && !pMtf )
7028 sal_uInt64 nPos = rStm.Tell();
7029 sal_uInt16 sz[4];
7030 rStm.ReadBytes( sz, 8 );
7031 Graphic aGraphic;
7032 if( ERRCODE_NONE == GraphicConverter::Import( rStm, aGraphic ) && aGraphic.GetType() != GraphicType::NONE )
7034 const GDIMetaFile& rMtf = aGraphic.GetGDIMetaFile();
7035 MakeContentStream( rDest.get(), rMtf );
7036 bMtfRead = true;
7038 // set behind the data
7039 rStm.Seek( nPos + nDataLen );
7041 else
7042 rStm.SeekRel( nDataLen );
7044 } while (rStm.good() && nReadLen >= nBytesRead);
7046 if( !bMtfRead && pMtf )
7048 MakeContentStream( rDest.get(), *pMtf );
7049 return true;
7052 return false;
7055 static const char* GetInternalServerName_Impl( const SvGlobalName& aGlobName )
7057 if ( aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_60 )
7058 || aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 ) )
7059 return "swriter";
7060 else if ( aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_60 )
7061 || aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 ) )
7062 return "scalc";
7063 else if ( aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_60 )
7064 || aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ) )
7065 return "simpress";
7066 else if ( aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_60 )
7067 || aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 ) )
7068 return "sdraw";
7069 else if ( aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_60 )
7070 || aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 ) )
7071 return "smath";
7072 else if ( aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_60 )
7073 || aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 ) )
7074 return "schart";
7075 return nullptr;
7078 OUString SvxMSDffManager::GetFilterNameFromClassID( const SvGlobalName& aGlobName )
7080 if ( aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_60 ) )
7081 return "StarOffice XML (Writer)";
7083 if ( aGlobName == SvGlobalName( SO3_SW_OLE_EMBED_CLASSID_8 ) )
7084 return "writer8";
7086 if ( aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_60 ) )
7087 return "StarOffice XML (Calc)";
7089 if ( aGlobName == SvGlobalName( SO3_SC_OLE_EMBED_CLASSID_8 ) )
7090 return "calc8";
7092 if ( aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_60 ) )
7093 return "StarOffice XML (Impress)";
7095 if ( aGlobName == SvGlobalName( SO3_SIMPRESS_OLE_EMBED_CLASSID_8 ) )
7096 return "impress8";
7098 if ( aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_60 ) )
7099 return "StarOffice XML (Draw)";
7101 if ( aGlobName == SvGlobalName( SO3_SDRAW_OLE_EMBED_CLASSID_8 ) )
7102 return "draw8";
7104 if ( aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_60 ) )
7105 return "StarOffice XML (Math)";
7107 if ( aGlobName == SvGlobalName( SO3_SM_OLE_EMBED_CLASSID_8 ) )
7108 return "math8";
7110 if ( aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_60 ) )
7111 return "StarOffice XML (Chart)";
7113 if ( aGlobName == SvGlobalName( SO3_SCH_OLE_EMBED_CLASSID_8 ) )
7114 return "chart8";
7116 return OUString();
7119 void SvxMSDffManager::ExtractOwnStream(SotStorage& rSrcStg, SvMemoryStream& rMemStream)
7121 tools::SvRef<SotStorageStream> xStr
7122 = rSrcStg.OpenSotStream("package_stream", StreamMode::STD_READ);
7123 xStr->ReadStream(rMemStream);
7126 css::uno::Reference < css::embed::XEmbeddedObject > SvxMSDffManager::CheckForConvertToSOObj( sal_uInt32 nConvertFlags,
7127 SotStorage& rSrcStg, const uno::Reference < embed::XStorage >& rDestStorage,
7128 const Graphic& rGrf,
7129 const tools::Rectangle& rVisArea, OUString const& rBaseURL)
7131 uno::Reference < embed::XEmbeddedObject > xObj;
7132 SvGlobalName aStgNm = rSrcStg.GetClassName();
7133 const char* pName = GetInternalServerName_Impl( aStgNm );
7134 OUString sStarName;
7135 if ( pName )
7136 sStarName = OUString::createFromAscii( pName );
7137 else if ( nConvertFlags )
7139 static struct ObjImpType
7141 sal_uInt32 nFlag;
7142 const char* pFactoryNm;
7143 // GlobalNameId
7144 sal_uInt32 n1;
7145 sal_uInt16 n2, n3;
7146 sal_uInt8 b8, b9, b10, b11, b12, b13, b14, b15;
7147 } const aArr[] = {
7148 { OLE_MATHTYPE_2_STARMATH, "smath", MSO_EQUATION3_CLASSID },
7149 { OLE_MATHTYPE_2_STARMATH, "smath", MSO_EQUATION2_CLASSID },
7150 { OLE_WINWORD_2_STARWRITER, "swriter", MSO_WW8_CLASSID },
7151 // Excel table
7152 { OLE_EXCEL_2_STARCALC, "scalc", MSO_EXCEL5_CLASSID },
7153 { OLE_EXCEL_2_STARCALC, "scalc", MSO_EXCEL8_CLASSID },
7154 // 114465: additional Excel OLE chart classId to above.
7155 { OLE_EXCEL_2_STARCALC, "scalc", MSO_EXCEL8_CHART_CLASSID },
7156 // PowerPoint presentation
7157 { OLE_POWERPOINT_2_STARIMPRESS, "simpress", MSO_PPT8_CLASSID },
7158 // PowerPoint slide
7159 { OLE_POWERPOINT_2_STARIMPRESS, "simpress", MSO_PPT8_SLIDE_CLASSID },
7160 { 0, nullptr,
7161 0, 0, 0,
7162 0, 0, 0, 0, 0, 0, 0, 0 }
7165 for( const ObjImpType* pArr = aArr; pArr->nFlag; ++pArr )
7167 if( nConvertFlags & pArr->nFlag )
7169 SvGlobalName aTypeName( pArr->n1, pArr->n2, pArr->n3,
7170 pArr->b8, pArr->b9, pArr->b10, pArr->b11,
7171 pArr->b12, pArr->b13, pArr->b14, pArr->b15 );
7173 if ( aStgNm == aTypeName )
7175 sStarName = OUString::createFromAscii( pArr->pFactoryNm );
7176 break;
7182 if ( sStarName.getLength() )
7184 //TODO/MBA: check if (and when) storage and stream will be destroyed!
7185 std::shared_ptr<const SfxFilter> pFilter;
7186 SvMemoryStream aMemStream;
7187 if ( pName )
7189 // TODO/LATER: perhaps we need to retrieve VisArea and Metafile from the storage also
7190 SvxMSDffManager::ExtractOwnStream(rSrcStg, aMemStream);
7192 else
7194 tools::SvRef<SotStorage> xStorage = new SotStorage( false, aMemStream );
7195 rSrcStg.CopyTo( xStorage.get() );
7196 xStorage->Commit();
7197 xStorage.clear();
7198 OUString aType = SfxFilter::GetTypeFromStorage( rSrcStg );
7199 if (aType.getLength() && !utl::ConfigManager::IsFuzzing())
7201 SfxFilterMatcher aMatch( sStarName );
7202 pFilter = aMatch.GetFilter4EA( aType );
7206 #ifdef DEBUG_FILTER_MSFILTER
7207 // extract embedded ole streams into "/tmp/embedded_stream_NNN"
7208 static sal_Int32 nOleCount(0);
7209 OUString aTmpName("/tmp/embedded_stream_");
7210 aTmpName += OUString::number(nOleCount++);
7211 aTmpName += ".bin";
7212 SvFileStream aTmpStream(aTmpName,StreamMode::READ|StreamMode::WRITE|StreamMode::TRUNC);
7213 xMemStream->Seek(0);
7214 aTmpStream.WriteStream(*xMemStream);
7215 aTmpStream.Close();
7216 #endif
7217 if ( pName || pFilter )
7219 //Reuse current ole name
7220 OUString aDstStgName = MSO_OLE_Obj + OUString::number(nMSOleObjCntr);
7222 OUString aFilterName;
7223 if ( pFilter )
7224 aFilterName = pFilter->GetName();
7225 else
7226 aFilterName = SvxMSDffManager::GetFilterNameFromClassID( aStgNm );
7228 uno::Sequence<beans::PropertyValue> aMedium(aFilterName.isEmpty() ? 3 : 4);
7229 auto pMedium = aMedium.getArray();
7230 pMedium[0].Name = "InputStream";
7231 uno::Reference < io::XInputStream > xStream = new ::utl::OSeekableInputStreamWrapper( aMemStream );
7232 pMedium[0].Value <<= xStream;
7233 pMedium[1].Name = "URL";
7234 pMedium[1].Value <<= OUString( "private:stream" );
7235 pMedium[2].Name = "DocumentBaseURL";
7236 pMedium[2].Value <<= rBaseURL;
7238 if ( !aFilterName.isEmpty() )
7240 pMedium[3].Name = "FilterName";
7241 pMedium[3].Value <<= aFilterName;
7244 OUString aName( aDstStgName );
7245 comphelper::EmbeddedObjectContainer aCnt( rDestStorage );
7246 xObj = aCnt.InsertEmbeddedObject(aMedium, aName, &rBaseURL);
7248 if ( !xObj.is() )
7250 if( !aFilterName.isEmpty() )
7252 // throw the filter parameter away as workaround
7253 aMedium.realloc( 2 );
7254 xObj = aCnt.InsertEmbeddedObject(aMedium, aName, &rBaseURL);
7257 if ( !xObj.is() )
7258 return xObj;
7261 // JP 26.10.2001: Bug 93374 / 91928 the writer
7262 // objects need the correct visarea needs the
7263 // correct visarea, but this is not true for
7264 // PowerPoint (see bugdoc 94908b)
7265 // SJ: 19.11.2001 bug 94908, also chart objects
7266 // needs the correct visarea
7268 // If pName is set this is an own embedded object, it should have the correct size internally
7269 // TODO/LATER: it might make sense in future to set the size stored in internal object
7270 if( !pName && ( sStarName == "swriter" || sStarName == "scalc" ) )
7272 // TODO/LATER: ViewAspect must be passed from outside!
7273 sal_Int64 nViewAspect = embed::Aspects::MSOLE_CONTENT;
7274 MapMode aMapMode( VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nViewAspect ) ) );
7275 Size aSz;
7276 if ( rVisArea.IsEmpty() )
7277 aSz = lcl_GetPrefSize(rGrf, aMapMode );
7278 else
7280 aSz = rVisArea.GetSize();
7281 aSz = OutputDevice::LogicToLogic( aSz, MapMode( MapUnit::Map100thMM ), aMapMode );
7284 // don't modify the object
7285 //TODO/LATER: remove those hacks, that needs to be done differently!
7286 //xIPObj->EnableSetModified( sal_False );
7287 awt::Size aSize;
7288 aSize.Width = aSz.Width();
7289 aSize.Height = aSz.Height();
7290 xObj->setVisualAreaSize( nViewAspect, aSize );
7291 //xIPObj->EnableSetModified( sal_True );
7293 else if ( sStarName == "smath" )
7294 { // SJ: force the object to recalc its visarea
7295 //TODO/LATER: wait for PrinterChangeNotification
7296 //xIPObj->OnDocumentPrinterChanged( NULL );
7301 return xObj;
7304 // TODO/MBA: code review and testing!
7305 rtl::Reference<SdrOle2Obj> SvxMSDffManager::CreateSdrOLEFromStorage(
7306 SdrModel& rSdrModel,
7307 const OUString& rStorageName,
7308 tools::SvRef<SotStorage> const & rSrcStorage,
7309 const uno::Reference < embed::XStorage >& xDestStorage,
7310 const Graphic& rGrf,
7311 const tools::Rectangle& rBoundRect,
7312 const tools::Rectangle& rVisArea,
7313 SvStream* pDataStrm,
7314 ErrCode& rError,
7315 sal_uInt32 nConvertFlags,
7316 sal_Int64 nRecommendedAspect,
7317 OUString const& rBaseURL)
7319 sal_Int64 nAspect = nRecommendedAspect;
7320 rtl::Reference<SdrOle2Obj> pRet;
7321 if( rSrcStorage.is() && xDestStorage.is() && rStorageName.getLength() )
7323 comphelper::EmbeddedObjectContainer aCnt( xDestStorage );
7324 // does the 01Ole-Stream exist at all?
7325 // (that's not the case for e.g. Fontwork )
7326 // If that's not the case -> include it as graphic
7327 bool bValidStorage = false;
7328 OUString aDstStgName = MSO_OLE_Obj + OUString::number( ++nMSOleObjCntr );
7331 tools::SvRef<SotStorage> xObjStg = rSrcStorage->OpenSotStorage( rStorageName );
7332 if( xObjStg.is() )
7335 sal_uInt8 aTestA[10]; // exist the \1CompObj-Stream ?
7336 tools::SvRef<SotStorageStream> xSrcTst = xObjStg->OpenSotStream( "\1CompObj" );
7337 bValidStorage = xSrcTst.is() && sizeof( aTestA ) ==
7338 xSrcTst->ReadBytes(aTestA, sizeof(aTestA));
7339 if( !bValidStorage )
7341 // or the \1Ole-Stream ?
7342 xSrcTst = xObjStg->OpenSotStream( "\1Ole" );
7343 bValidStorage = xSrcTst.is() && sizeof(aTestA) ==
7344 xSrcTst->ReadBytes(aTestA, sizeof(aTestA));
7348 if( bValidStorage )
7350 if ( nAspect != embed::Aspects::MSOLE_ICON )
7352 // check whether the object is iconified one
7353 // usually this information is already known, the only exception
7354 // is a kind of embedded objects in Word documents
7355 // TODO/LATER: should the caller be notified if the aspect changes in future?
7357 tools::SvRef<SotStorageStream> xObjInfoSrc = xObjStg->OpenSotStream(
7358 "\3ObjInfo", StreamMode::STD_READ );
7359 if ( xObjInfoSrc.is() && !xObjInfoSrc->GetError() )
7361 sal_uInt8 nByte = 0;
7362 xObjInfoSrc->ReadUChar( nByte );
7363 if ( ( nByte >> 4 ) & embed::Aspects::MSOLE_ICON )
7364 nAspect = embed::Aspects::MSOLE_ICON;
7368 uno::Reference < embed::XEmbeddedObject > xObj( CheckForConvertToSOObj(
7369 nConvertFlags, *xObjStg, xDestStorage, rGrf,
7370 rVisArea, rBaseURL));
7371 if ( xObj.is() )
7373 // remember file name to use in the title bar
7374 INetURLObject aURL(rBaseURL);
7375 xObj->setContainerName(aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset));
7377 svt::EmbeddedObjectRef aObj( xObj, nAspect );
7379 // TODO/LATER: need MediaType
7380 aObj.SetGraphic( rGrf, OUString() );
7382 // TODO/MBA: check setting of PersistName
7383 pRet = new SdrOle2Obj(
7384 rSdrModel,
7385 aObj,
7386 OUString(),
7387 rBoundRect);
7389 // we have the Object, don't create another
7390 bValidStorage = false;
7396 if( bValidStorage )
7398 // object is not an own object
7399 tools::SvRef<SotStorage> xObjStor = SotStorage::OpenOLEStorage( xDestStorage, aDstStgName, StreamMode::READWRITE );
7401 if ( xObjStor.is() )
7403 tools::SvRef<SotStorage> xSrcStor = rSrcStorage->OpenSotStorage( rStorageName, StreamMode::READ );
7404 xSrcStor->CopyTo( xObjStor.get() );
7406 if( !xObjStor->GetError() )
7407 xObjStor->Commit();
7409 if( xObjStor->GetError() )
7411 rError = xObjStor->GetError();
7412 bValidStorage = false;
7414 else if( !xObjStor.is() )
7415 bValidStorage = false;
7418 else if( pDataStrm )
7420 sal_uInt32 nLen(0), nDummy(0);
7421 pDataStrm->ReadUInt32( nLen ).ReadUInt32( nDummy );
7422 if( ERRCODE_NONE != pDataStrm->GetError() ||
7423 // Id in BugDoc - exist there other Ids?
7424 // The ConvertToOle2 - does not check for consistent
7425 0x30008 != nDummy )
7426 bValidStorage = false;
7427 else
7429 // or is it an OLE-1 Stream in the DataStream?
7430 tools::SvRef<SotStorage> xObjStor = SotStorage::OpenOLEStorage( xDestStorage, aDstStgName );
7431 //TODO/MBA: remove metafile conversion from ConvertToOle2
7432 //when is this code used?!
7433 GDIMetaFile aMtf;
7434 bValidStorage = ConvertToOle2( *pDataStrm, nLen, &aMtf, xObjStor );
7435 xObjStor->Commit();
7439 if( bValidStorage )
7441 uno::Reference < embed::XEmbeddedObject > xObj = aCnt.GetEmbeddedObject( aDstStgName );
7442 if( xObj.is() )
7444 // remember file name to use in the title bar
7445 INetURLObject aURL( rBaseURL );
7446 xObj->setContainerName( aURL.GetLastName( INetURLObject::DecodeMechanism::WithCharset ) );
7448 // the visual area must be retrieved from the metafile (object doesn't know it so far)
7450 if ( nAspect != embed::Aspects::MSOLE_ICON )
7452 // working with visual area can switch the object to running state
7455 awt::Size aAwtSz;
7456 // the provided visual area should be used, if there is any
7457 if ( rVisArea.IsEmpty() )
7459 MapUnit aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
7460 Size aSz(lcl_GetPrefSize(rGrf, MapMode(aMapUnit)));
7461 aAwtSz.Width = aSz.Width();
7462 aAwtSz.Height = aSz.Height();
7464 else
7466 aAwtSz.Width = rVisArea.GetWidth();
7467 aAwtSz.Height = rVisArea.GetHeight();
7469 //xInplaceObj->EnableSetModified( sal_False );
7470 xObj->setVisualAreaSize( nAspect, aAwtSz );
7471 //xInplaceObj->EnableSetModified( sal_True );
7473 catch( const uno::Exception& )
7475 OSL_FAIL( "Could not set visual area of the object!" );
7479 svt::EmbeddedObjectRef aObj( xObj, nAspect );
7481 // TODO/LATER: need MediaType
7482 aObj.SetGraphic( rGrf, OUString() );
7484 pRet = new SdrOle2Obj(
7485 rSdrModel,
7486 aObj,
7487 aDstStgName,
7488 rBoundRect);
7493 return pRet;
7496 bool SvxMSDffManager::SetPropValue( const uno::Any& rAny, const uno::Reference< css::beans::XPropertySet > & rXPropSet,
7497 const OUString& rPropName )
7499 bool bRetValue = false;
7502 uno::Reference< beans::XPropertySetInfo >
7503 aXPropSetInfo( rXPropSet->getPropertySetInfo() );
7504 if ( aXPropSetInfo.is() )
7505 bRetValue = aXPropSetInfo->hasPropertyByName( rPropName );
7507 catch( const uno::Exception& )
7509 bRetValue = false;
7511 if ( bRetValue )
7515 rXPropSet->setPropertyValue( rPropName, rAny );
7516 bRetValue = true;
7518 catch( const uno::Exception& )
7520 bRetValue = false;
7523 return bRetValue;
7526 SvxMSDffImportRec::SvxMSDffImportRec()
7527 : nClientAnchorLen( 0 ),
7528 nClientDataLen( 0 ),
7529 nXAlign( 0 ), // position n cm from left
7530 nYAlign( 0 ), // position n cm below
7531 nGroupShapeBooleanProperties(0), // 16 settings: LayoutInCell/AllowOverlap/BehindDocument...
7532 nFlags( ShapeFlag::NONE ),
7533 nDxTextLeft( 144 ),
7534 nDyTextTop( 72 ),
7535 nDxTextRight( 144 ),
7536 nDyTextBottom( 72 ),
7537 nDxWrapDistLeft( 0 ),
7538 nDyWrapDistTop( 0 ),
7539 nDxWrapDistRight( 0 ),
7540 nDyWrapDistBottom(0 ),
7541 nCropFromTop( 0 ),
7542 nCropFromBottom( 0 ),
7543 nCropFromLeft( 0 ),
7544 nCropFromRight( 0 ),
7545 nNextShapeId( 0 ),
7546 nShapeId( 0 ),
7547 eShapeType( mso_sptNil ),
7548 relativeHorizontalWidth( -1 ),
7549 isHorizontalRule( false )
7551 eLineStyle = mso_lineSimple; // GPF-Bug #66227#
7552 eLineDashing = mso_lineSolid;
7553 bDrawHell = false;
7554 bHidden = false;
7556 bReplaceByFly = false;
7557 bVFlip = false;
7558 bHFlip = false;
7559 bAutoWidth = false;
7562 SvxMSDffImportRec::SvxMSDffImportRec(const SvxMSDffImportRec& rCopy)
7563 : pObj( rCopy.pObj ),
7564 nXAlign( rCopy.nXAlign ),
7565 nXRelTo( rCopy.nXRelTo ),
7566 nYAlign( rCopy.nYAlign ),
7567 nYRelTo( rCopy.nYRelTo ),
7568 nGroupShapeBooleanProperties(rCopy.nGroupShapeBooleanProperties),
7569 nFlags( rCopy.nFlags ),
7570 nDxTextLeft( rCopy.nDxTextLeft ),
7571 nDyTextTop( rCopy.nDyTextTop ),
7572 nDxTextRight( rCopy.nDxTextRight ),
7573 nDyTextBottom( rCopy.nDyTextBottom ),
7574 nDxWrapDistLeft( rCopy.nDxWrapDistLeft ),
7575 nDyWrapDistTop( rCopy.nDyWrapDistTop ),
7576 nDxWrapDistRight( rCopy.nDxWrapDistRight ),
7577 nDyWrapDistBottom(rCopy.nDyWrapDistBottom ),
7578 nCropFromTop( rCopy.nCropFromTop ),
7579 nCropFromBottom( rCopy.nCropFromBottom ),
7580 nCropFromLeft( rCopy.nCropFromLeft ),
7581 nCropFromRight( rCopy.nCropFromRight ),
7582 aTextId( rCopy.aTextId ),
7583 nNextShapeId( rCopy.nNextShapeId ),
7584 nShapeId( rCopy.nShapeId ),
7585 eShapeType( rCopy.eShapeType ),
7586 relativeHorizontalWidth( rCopy.relativeHorizontalWidth ),
7587 isHorizontalRule( rCopy.isHorizontalRule )
7589 eLineStyle = rCopy.eLineStyle; // GPF-Bug #66227#
7590 eLineDashing = rCopy.eLineDashing;
7591 bDrawHell = rCopy.bDrawHell;
7592 bHidden = rCopy.bHidden;
7593 bReplaceByFly = rCopy.bReplaceByFly;
7594 bAutoWidth = rCopy.bAutoWidth;
7595 bVFlip = rCopy.bVFlip;
7596 bHFlip = rCopy.bHFlip;
7597 nClientAnchorLen = rCopy.nClientAnchorLen;
7598 if( rCopy.nClientAnchorLen )
7600 pClientAnchorBuffer.reset( new char[ nClientAnchorLen ] );
7601 memcpy( pClientAnchorBuffer.get(),
7602 rCopy.pClientAnchorBuffer.get(),
7603 nClientAnchorLen );
7605 else
7606 pClientAnchorBuffer = nullptr;
7608 nClientDataLen = rCopy.nClientDataLen;
7609 if( rCopy.nClientDataLen )
7611 pClientDataBuffer.reset( new char[ nClientDataLen ] );
7612 memcpy( pClientDataBuffer.get(),
7613 rCopy.pClientDataBuffer.get(),
7614 nClientDataLen );
7616 else
7617 pClientDataBuffer = nullptr;
7619 if (rCopy.pWrapPolygon)
7620 pWrapPolygon = rCopy.pWrapPolygon;
7623 SvxMSDffImportRec::~SvxMSDffImportRec()
7627 void SvxMSDffManager::insertShapeId( sal_Int32 nShapeId, SdrObject* pShape )
7629 maShapeIdContainer[nShapeId] = pShape;
7632 void SvxMSDffManager::removeShapeId( SdrObject const * pShape )
7634 SvxMSDffShapeIdContainer::iterator aIter = std::find_if(maShapeIdContainer.begin(), maShapeIdContainer.end(),
7635 [&pShape](const SvxMSDffShapeIdContainer::value_type& rEntry) { return rEntry.second == pShape; });
7636 if (aIter != maShapeIdContainer.end())
7637 maShapeIdContainer.erase( aIter );
7640 SdrObject* SvxMSDffManager::getShapeForId( sal_Int32 nShapeId )
7642 SvxMSDffShapeIdContainer::iterator aIter( maShapeIdContainer.find(nShapeId) );
7643 return aIter != maShapeIdContainer.end() ? (*aIter).second : nullptr;
7646 SvxMSDffImportData::SvxMSDffImportData(const tools::Rectangle& rParentRect)
7647 : aParentRect(rParentRect)
7651 SvxMSDffImportData::~SvxMSDffImportData()
7655 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */