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