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