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