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 <sal/config.h> 21 #include <sal/log.hxx> 22 23 #include <com/sun/star/util/CloseVetoException.hpp> 24 #include <com/sun/star/util/XCloseable.hpp> 25 26 #include <doc.hxx> 27 #include "writerhelper.hxx" 28 #include <msfilter.hxx> 29 #include <com/sun/star/container/XChild.hpp> 30 31 #include <algorithm> 32 #include <svl/itemiter.hxx> 33 #include <svx/svdobj.hxx> 34 #include <svx/svdoole2.hxx> 35 #include <svx/fmglob.hxx> 36 #include <editeng/formatbreakitem.hxx> 37 #include <editeng/tstpitem.hxx> 38 #include <ndtxt.hxx> 39 #include <ndnotxt.hxx> 40 #include <fmtcntnt.hxx> 41 #include <swtable.hxx> 42 #include <frmfmt.hxx> 43 #include <flypos.hxx> 44 #include <fmtanchr.hxx> 45 #include <ndgrf.hxx> 46 #include <fmtfsize.hxx> 47 #include <SwStyleNameMapper.hxx> 48 #include <docary.hxx> 49 #include <charfmt.hxx> 50 #include <fchrfmt.hxx> 51 #include <redline.hxx> 52 #include "types.hxx" 53 #include <unotools/streamwrap.hxx> 54 #include <svtools/embedhlp.hxx> 55 #include <numrule.hxx> 56 #include <vcl/svapp.hxx> 57 #include <IDocumentDrawModelAccess.hxx> 58 #include <IDocumentLayoutAccess.hxx> 59 #include <IDocumentStylePoolAccess.hxx> 60 #include <IDocumentMarkAccess.hxx> 61 #include <IMark.hxx> 62 63 using namespace com::sun::star; 64 65 namespace 66 { 67 // #i98791# - adjust sorting 68 // Utility to sort SwTextFormatColl's by their assigned outline style list level 69 class outlinecmp 70 { 71 public: operator ()(const SwTextFormatColl * pA,const SwTextFormatColl * pB) const72 bool operator()(const SwTextFormatColl *pA, const SwTextFormatColl *pB) const 73 { 74 // #i98791# 75 bool bResult( false ); 76 const bool bIsAAssignedToOutlineStyle( pA->IsAssignedToListLevelOfOutlineStyle() ); 77 const bool bIsBAssignedToOutlineStyle( pB->IsAssignedToListLevelOfOutlineStyle() ); 78 if ( bIsAAssignedToOutlineStyle != bIsBAssignedToOutlineStyle ) 79 { 80 bResult = bIsBAssignedToOutlineStyle; 81 } 82 else if ( !bIsAAssignedToOutlineStyle ) 83 { 84 // pA and pB are equal regarding the sorting criteria. 85 // Thus return value does not matter. 86 bResult = false; 87 } 88 else 89 { 90 bResult = pA->GetAssignedOutlineStyleLevel() < pB->GetAssignedOutlineStyleLevel(); 91 } 92 93 return bResult; 94 } 95 }; 96 IsValidSlotWhich(sal_uInt16 nSlotId,sal_uInt16 nWhichId)97 bool IsValidSlotWhich(sal_uInt16 nSlotId, sal_uInt16 nWhichId) 98 { 99 return (nSlotId != 0 && nWhichId != 0 && nSlotId != nWhichId); 100 } 101 102 /* 103 Utility to convert a SwPosFlyFrames into a simple vector of ww8::Frames 104 105 The crucial thing is that a ww8::Frame always has an anchor which 106 points to some content in the document. This is a requirement of exporting 107 to Word 108 */ SwPosFlyFramesToFrames(const SwPosFlyFrames & rFlys)109 ww8::Frames SwPosFlyFramesToFrames(const SwPosFlyFrames &rFlys) 110 { 111 ww8::Frames aRet; 112 113 for(const auto& rpFly : rFlys) 114 { 115 const SwFrameFormat &rEntry = rpFly->GetFormat(); 116 117 if (const SwPosition* pAnchor = rEntry.GetAnchor().GetContentAnchor()) 118 { 119 // the anchor position will be invalidated by SetRedlineFlags 120 // so set a dummy position and fix it in UpdateFramePositions 121 SwPosition const dummy(SwNodeIndex( 122 const_cast<SwNodes&>(pAnchor->nNode.GetNodes()))); 123 aRet.emplace_back(rEntry, dummy); 124 } 125 else 126 { 127 SwPosition aPos(rpFly->GetNdIndex()); 128 129 if (SwTextNode* pTextNd = aPos.nNode.GetNode().GetTextNode()) 130 { 131 aPos.nContent.Assign(pTextNd, 0); 132 } 133 134 aRet.emplace_back(rEntry, aPos); 135 } 136 } 137 return aRet; 138 } 139 140 //Utility to test if a frame is anchored at a given node index 141 class anchoredto 142 { 143 private: 144 sal_uLong const mnNode; 145 public: anchoredto(sal_uLong nNode)146 explicit anchoredto(sal_uLong nNode) : mnNode(nNode) {} operator ()(const ww8::Frame & rFrame) const147 bool operator()(const ww8::Frame &rFrame) const 148 { 149 return (mnNode == rFrame.GetPosition().nNode.GetNode().GetIndex()); 150 } 151 }; 152 } 153 154 namespace ww8 155 { 156 //For i120928,size conversion before exporting graphic of bullet Frame(const Graphic & rGrf,const SwPosition & rPos)157 Frame::Frame(const Graphic &rGrf, const SwPosition &rPos) 158 : mpFlyFrame(nullptr) 159 , maPos(rPos) 160 , maSize() 161 , maLayoutSize() 162 , meWriterType(eBulletGrf) 163 , mpStartFrameContent(nullptr) 164 , mbIsInline(true) 165 , mbForBullet(true) 166 , maGrf(rGrf) 167 { 168 const MapMode aMap100mm( MapUnit::Map100thMM ); 169 Size aSize( rGrf.GetPrefSize() ); 170 if ( MapUnit::MapPixel == rGrf.GetPrefMapMode().GetMapUnit() ) 171 { 172 aSize = Application::GetDefaultDevice()->PixelToLogic(aSize, aMap100mm ); 173 } 174 else 175 { 176 aSize = OutputDevice::LogicToLogic( aSize,rGrf.GetPrefMapMode(), aMap100mm ); 177 } 178 maSize = aSize; 179 maLayoutSize = maSize; 180 } 181 Frame(const SwFrameFormat & rFormat,const SwPosition & rPos)182 Frame::Frame(const SwFrameFormat &rFormat, const SwPosition &rPos) 183 : mpFlyFrame(&rFormat) 184 , maPos(rPos) 185 , maSize() 186 , maLayoutSize() // #i43447# 187 , meWriterType(eTextBox) 188 , mpStartFrameContent(nullptr) 189 // #i43447# - move to initialization list 190 , mbIsInline( (rFormat.GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR) ) 191 // #i120928# - handle graphic of bullet within existing implementation 192 , mbForBullet(false) 193 , maGrf() 194 { 195 switch (rFormat.Which()) 196 { 197 case RES_FLYFRMFMT: 198 if (const SwNodeIndex* pIdx = rFormat.GetContent().GetContentIdx()) 199 { 200 SwNodeIndex aIdx(*pIdx, 1); 201 const SwNode &rNd = aIdx.GetNode(); 202 // #i43447# - determine layout size 203 { 204 SwRect aLayRect( rFormat.FindLayoutRect() ); 205 tools::Rectangle aRect( aLayRect.SVRect() ); 206 // The Object is not rendered (e.g. something in unused 207 // header/footer) - thus, get the values from the format. 208 if ( aLayRect.IsEmpty() ) 209 { 210 aRect.SetSize( rFormat.GetFrameSize().GetSize() ); 211 } 212 maLayoutSize = aRect.GetSize(); 213 } 214 switch (rNd.GetNodeType()) 215 { 216 case SwNodeType::Grf: 217 meWriterType = eGraphic; 218 maSize = rNd.GetNoTextNode()->GetTwipSize(); 219 break; 220 case SwNodeType::Ole: 221 meWriterType = eOle; 222 maSize = rNd.GetNoTextNode()->GetTwipSize(); 223 break; 224 default: 225 meWriterType = eTextBox; 226 // #i43447# - Size equals layout size for text boxes 227 maSize = maLayoutSize; 228 break; 229 } 230 mpStartFrameContent = &rNd; 231 } 232 else 233 { 234 OSL_ENSURE(false, "Impossible"); 235 meWriterType = eTextBox; 236 } 237 break; 238 default: 239 if (const SdrObject* pObj = rFormat.FindRealSdrObject()) 240 { 241 if (pObj->GetObjInventor() == SdrInventor::FmForm) 242 meWriterType = eFormControl; 243 else 244 meWriterType = eDrawing; 245 maSize = pObj->GetSnapRect().GetSize(); 246 maLayoutSize = maSize; 247 } 248 else 249 { 250 OSL_ENSURE(false, "Impossible"); 251 meWriterType = eDrawing; 252 } 253 break; 254 } 255 } 256 257 ForceTreatAsInline()258 void Frame::ForceTreatAsInline() 259 { 260 mbIsInline = true; 261 } 262 } 263 264 namespace sw 265 { 266 namespace hack 267 { 268 TransformWhichBetweenPools(const SfxItemPool & rDestPool,const SfxItemPool & rSrcPool,sal_uInt16 nWhich)269 sal_uInt16 TransformWhichBetweenPools(const SfxItemPool &rDestPool, 270 const SfxItemPool &rSrcPool, sal_uInt16 nWhich) 271 { 272 sal_uInt16 nSlotId = rSrcPool.GetSlotId(nWhich); 273 if (IsValidSlotWhich(nSlotId, nWhich)) 274 nWhich = rDestPool.GetWhich(nSlotId); 275 else 276 nWhich = 0; 277 return nWhich; 278 } 279 GetSetWhichFromSwDocWhich(const SfxItemSet & rSet,const SwDoc & rDoc,sal_uInt16 nWhich)280 sal_uInt16 GetSetWhichFromSwDocWhich(const SfxItemSet &rSet, 281 const SwDoc &rDoc, sal_uInt16 nWhich) 282 { 283 if (RES_WHICHHINT_END < *(rSet.GetRanges())) 284 { 285 nWhich = TransformWhichBetweenPools(*rSet.GetPool(), 286 rDoc.GetAttrPool(), nWhich); 287 } 288 return nWhich; 289 } 290 DrawingOLEAdaptor(SdrOle2Obj & rObj,SfxObjectShell & rPers)291 DrawingOLEAdaptor::DrawingOLEAdaptor(SdrOle2Obj &rObj, 292 SfxObjectShell &rPers) 293 : mxIPRef(rObj.GetObjRef()), mrPers(rPers), 294 mpGraphic( rObj.GetGraphic() ) 295 { 296 rObj.AbandonObject(); 297 } 298 TransferToDoc(OUString & rName)299 bool DrawingOLEAdaptor::TransferToDoc( OUString &rName ) 300 { 301 OSL_ENSURE(mxIPRef.is(), "Transferring invalid object to doc"); 302 if (!mxIPRef.is()) 303 return false; 304 305 uno::Reference < container::XChild > xChild( mxIPRef, uno::UNO_QUERY ); 306 if ( xChild.is() ) 307 xChild->setParent( mrPers.GetModel() ); 308 309 bool bSuccess = mrPers.GetEmbeddedObjectContainer().InsertEmbeddedObject( mxIPRef, rName ); 310 if (bSuccess) 311 { 312 if ( mpGraphic ) 313 ::svt::EmbeddedObjectRef::SetGraphicToContainer( *mpGraphic, 314 mrPers.GetEmbeddedObjectContainer(), 315 rName, 316 OUString() ); 317 318 mxIPRef = nullptr; 319 } 320 321 return bSuccess; 322 } 323 ~DrawingOLEAdaptor()324 DrawingOLEAdaptor::~DrawingOLEAdaptor() 325 { 326 if (mxIPRef.is()) 327 { 328 OSL_ENSURE( !mrPers.GetEmbeddedObjectContainer().HasEmbeddedObject( mxIPRef ), "Object in adaptor is inserted?!" ); 329 try 330 { 331 mxIPRef->close(true); 332 } 333 catch ( const css::util::CloseVetoException& ) 334 { 335 } 336 337 mxIPRef = nullptr; 338 } 339 } 340 } 341 342 namespace util 343 { MakeSafePositioningValue(SwTwips nIn)344 SwTwips MakeSafePositioningValue(SwTwips nIn) 345 { 346 if (nIn > SHRT_MAX) 347 nIn = SHRT_MAX; 348 else if (nIn < SHRT_MIN) 349 nIn = SHRT_MIN; 350 return nIn; 351 } 352 SendObjectToHell(SdrObject & rObject) const353 void SetLayer::SendObjectToHell(SdrObject &rObject) const 354 { 355 SetObjectLayer(rObject, eHell); 356 } 357 SendObjectToHeaven(SdrObject & rObject) const358 void SetLayer::SendObjectToHeaven(SdrObject &rObject) const 359 { 360 SetObjectLayer(rObject, eHeaven); 361 } 362 SetObjectLayer(SdrObject & rObject,Layer eLayer) const363 void SetLayer::SetObjectLayer(SdrObject &rObject, Layer eLayer) const 364 { 365 if (SdrInventor::FmForm == rObject.GetObjInventor()) 366 rObject.SetLayer(mnFormLayer); 367 else 368 { 369 switch (eLayer) 370 { 371 case eHeaven: 372 rObject.SetLayer(mnHeavenLayer); 373 break; 374 case eHell: 375 rObject.SetLayer(mnHellLayer); 376 break; 377 } 378 } 379 } 380 381 //SetLayer boilerplate begin 382 383 // #i38889# - by default put objects into the invisible layers. SetLayer(const SwDoc & rDoc)384 SetLayer::SetLayer(const SwDoc &rDoc) 385 : mnHeavenLayer(rDoc.getIDocumentDrawModelAccess().GetInvisibleHeavenId()), 386 mnHellLayer(rDoc.getIDocumentDrawModelAccess().GetInvisibleHellId()), 387 mnFormLayer(rDoc.getIDocumentDrawModelAccess().GetInvisibleControlsId()) 388 { 389 } 390 //SetLayer boilerplate end 391 GetPoolItems(const SfxItemSet & rSet,ww8::PoolItems & rItems,bool bExportParentItemSet)392 void GetPoolItems(const SfxItemSet &rSet, ww8::PoolItems &rItems, bool bExportParentItemSet ) 393 { 394 if( bExportParentItemSet ) 395 { 396 sal_uInt16 nTotal = rSet.TotalCount(); 397 for( sal_uInt16 nItem =0; nItem < nTotal; ++nItem ) 398 { 399 const SfxPoolItem* pItem = nullptr; 400 if( SfxItemState::SET == rSet.GetItemState( rSet.GetWhichByPos( nItem ), true, &pItem ) ) 401 { 402 rItems[pItem->Which()] = pItem; 403 } 404 } 405 } 406 else if( rSet.Count()) 407 { 408 SfxItemIter aIter(rSet); 409 if (const SfxPoolItem *pItem = aIter.GetCurItem()) 410 { 411 do 412 rItems[pItem->Which()] = pItem; 413 while ((pItem = aIter.NextItem())); 414 } 415 } 416 } 417 SearchPoolItems(const ww8::PoolItems & rItems,sal_uInt16 eType)418 const SfxPoolItem *SearchPoolItems(const ww8::PoolItems &rItems, 419 sal_uInt16 eType) 420 { 421 auto aIter = rItems.find(eType); 422 if (aIter != rItems.end()) 423 return aIter->second; 424 return nullptr; 425 } 426 ClearOverridesFromSet(const SwFormatCharFormat & rFormat,SfxItemSet & rSet)427 void ClearOverridesFromSet(const SwFormatCharFormat &rFormat, SfxItemSet &rSet) 428 { 429 if (const SwCharFormat* pCharFormat = rFormat.GetCharFormat()) 430 { 431 if (pCharFormat->GetAttrSet().Count()) 432 { 433 SfxItemIter aIter(pCharFormat->GetAttrSet()); 434 const SfxPoolItem *pItem = aIter.GetCurItem(); 435 do 436 rSet.ClearItem(pItem->Which()); 437 while ((pItem = aIter.NextItem())); 438 } 439 } 440 } 441 GetParaStyles(const SwDoc & rDoc)442 ww8::ParaStyles GetParaStyles(const SwDoc &rDoc) 443 { 444 ww8::ParaStyles aStyles; 445 typedef ww8::ParaStyles::size_type mysizet; 446 447 const SwTextFormatColls *pColls = rDoc.GetTextFormatColls(); 448 mysizet nCount = pColls ? pColls->size() : 0; 449 aStyles.reserve(nCount); 450 for (mysizet nI = 0; nI < nCount; ++nI) 451 aStyles.push_back((*pColls)[ static_cast< sal_uInt16 >(nI) ]); 452 return aStyles; 453 } 454 GetParaStyle(SwDoc & rDoc,const OUString & rName)455 SwTextFormatColl* GetParaStyle(SwDoc &rDoc, const OUString& rName) 456 { 457 // Search first in the Doc-Styles 458 SwTextFormatColl* pColl = rDoc.FindTextFormatCollByName(rName); 459 if (!pColl) 460 { 461 // Collection not found, try in Pool ? 462 sal_uInt16 n = SwStyleNameMapper::GetPoolIdFromUIName(rName, 463 SwGetPoolIdFromName::TxtColl); 464 if (n != SAL_MAX_UINT16) // found or standard 465 pColl = rDoc.getIDocumentStylePoolAccess().GetTextCollFromPool(n, false); 466 } 467 return pColl; 468 } 469 GetCharStyle(SwDoc & rDoc,const OUString & rName)470 SwCharFormat* GetCharStyle(SwDoc &rDoc, const OUString& rName) 471 { 472 SwCharFormat *pFormat = rDoc.FindCharFormatByName(rName); 473 if (!pFormat) 474 { 475 // Collection not found, try in Pool ? 476 sal_uInt16 n = SwStyleNameMapper::GetPoolIdFromUIName(rName, 477 SwGetPoolIdFromName::ChrFmt); 478 if (n != SAL_MAX_UINT16) // found or standard 479 pFormat = rDoc.getIDocumentStylePoolAccess().GetCharFormatFromPool(n); 480 } 481 return pFormat; 482 } 483 484 // #i98791# - adjust sorting algorithm SortByAssignedOutlineStyleListLevel(ww8::ParaStyles & rStyles)485 void SortByAssignedOutlineStyleListLevel(ww8::ParaStyles &rStyles) 486 { 487 std::sort(rStyles.begin(), rStyles.end(), outlinecmp()); 488 } 489 490 /* 491 Utility to extract FlyFormats from a document, potentially from a 492 selection. 493 */ GetFrames(const SwDoc & rDoc,SwPaM const * pPaM)494 ww8::Frames GetFrames(const SwDoc &rDoc, SwPaM const *pPaM /*, bool bAll*/) 495 { 496 SwPosFlyFrames aFlys(rDoc.GetAllFlyFormats(pPaM, true)); 497 ww8::Frames aRet(SwPosFlyFramesToFrames(aFlys)); 498 return aRet; 499 } 500 UpdateFramePositions(ww8::Frames & rFrames)501 void UpdateFramePositions(ww8::Frames & rFrames) 502 { 503 for (ww8::Frame & rFrame : rFrames) 504 { 505 SwFormatAnchor const& rAnchor = rFrame.GetFrameFormat().GetAnchor(); 506 if (SwPosition const*const pAnchor = rAnchor.GetContentAnchor()) 507 { 508 rFrame.SetPosition(*pAnchor); 509 } 510 else 511 { // these don't need to be corrected, they're not in redlines 512 assert(RndStdIds::FLY_AT_PAGE == rAnchor.GetAnchorId()); 513 } 514 } 515 } 516 GetFramesInNode(const ww8::Frames & rFrames,const SwNode & rNode)517 ww8::Frames GetFramesInNode(const ww8::Frames &rFrames, const SwNode &rNode) 518 { 519 ww8::Frames aRet; 520 std::copy_if(rFrames.begin(), rFrames.end(), 521 std::back_inserter(aRet), anchoredto(rNode.GetIndex())); 522 return aRet; 523 } 524 GetNumFormatFromSwNumRuleLevel(const SwNumRule & rRule,int nLevel)525 const SwNumFormat* GetNumFormatFromSwNumRuleLevel(const SwNumRule &rRule, 526 int nLevel) 527 { 528 if (nLevel < 0 || nLevel >= MAXLEVEL) 529 { 530 OSL_FAIL("Invalid level"); 531 return nullptr; 532 } 533 return &(rRule.Get( static_cast< sal_uInt16 >(nLevel) )); 534 } 535 GetNumFormatFromTextNode(const SwTextNode & rTextNode)536 const SwNumFormat* GetNumFormatFromTextNode(const SwTextNode &rTextNode) 537 { 538 const SwNumRule *pRule = nullptr; 539 if ( 540 rTextNode.IsNumbered() && rTextNode.IsCountedInList() && 541 nullptr != (pRule = rTextNode.GetNumRule()) 542 ) 543 { 544 return GetNumFormatFromSwNumRuleLevel(*pRule, 545 rTextNode.GetActualListLevel()); 546 } 547 548 OSL_ENSURE(rTextNode.GetDoc(), "No document for node?, suspicious"); 549 if (!rTextNode.GetDoc()) 550 return nullptr; 551 552 if ( 553 rTextNode.IsNumbered() && rTextNode.IsCountedInList() && 554 nullptr != (pRule = rTextNode.GetDoc()->GetOutlineNumRule()) 555 ) 556 { 557 return GetNumFormatFromSwNumRuleLevel(*pRule, 558 rTextNode.GetActualListLevel()); 559 } 560 561 return nullptr; 562 } 563 GetNumRuleFromTextNode(const SwTextNode & rTextNode)564 const SwNumRule* GetNumRuleFromTextNode(const SwTextNode &rTextNode) 565 { 566 return GetNormalNumRuleFromTextNode(rTextNode); 567 } 568 GetNormalNumRuleFromTextNode(const SwTextNode & rTextNode)569 const SwNumRule* GetNormalNumRuleFromTextNode(const SwTextNode &rTextNode) 570 { 571 const SwNumRule *pRule = nullptr; 572 573 if ( 574 rTextNode.IsNumbered() && rTextNode.IsCountedInList() && 575 nullptr != (pRule = rTextNode.GetNumRule()) 576 ) 577 { 578 return pRule; 579 } 580 return nullptr; 581 } 582 GetNoTextNodeFromSwFrameFormat(const SwFrameFormat & rFormat)583 SwNoTextNode *GetNoTextNodeFromSwFrameFormat(const SwFrameFormat &rFormat) 584 { 585 const SwNodeIndex *pIndex = rFormat.GetContent().GetContentIdx(); 586 OSL_ENSURE(pIndex, "No NodeIndex in SwFrameFormat ?, suspicious"); 587 if (!pIndex) 588 return nullptr; 589 SwNodeIndex aIdx(*pIndex, 1); 590 return aIdx.GetNode().GetNoTextNode(); 591 } 592 HasPageBreak(const SwNode & rNd)593 bool HasPageBreak(const SwNode &rNd) 594 { 595 const SvxFormatBreakItem *pBreak = nullptr; 596 if (rNd.IsTableNode() && rNd.GetTableNode()) 597 { 598 const SwTable& rTable = rNd.GetTableNode()->GetTable(); 599 const SwFrameFormat* pApply = rTable.GetFrameFormat(); 600 OSL_ENSURE(pApply, "impossible"); 601 if (pApply) 602 pBreak = &(ItemGet<SvxFormatBreakItem>(*pApply, RES_BREAK)); 603 } 604 else if (const SwContentNode *pNd = rNd.GetContentNode()) 605 pBreak = &(ItemGet<SvxFormatBreakItem>(*pNd, RES_BREAK)); 606 607 return pBreak && pBreak->GetBreak() == SvxBreak::PageBefore; 608 } 609 PolygonFromPolyPolygon(const tools::PolyPolygon & rPolyPoly)610 tools::Polygon PolygonFromPolyPolygon(const tools::PolyPolygon &rPolyPoly) 611 { 612 if(1 == rPolyPoly.Count()) 613 { 614 return rPolyPoly[0]; 615 } 616 else 617 { 618 // This method will now just concatenate the polygons contained 619 // in the given PolyPolygon. Anything else which might be thought of 620 // for reducing to a single polygon will just need more power and 621 // cannot create more correct results. 622 sal_uInt32 nPointCount(0); 623 sal_uInt16 a; 624 625 for(a = 0; a < rPolyPoly.Count(); a++) 626 { 627 nPointCount += static_cast<sal_uInt32>(rPolyPoly[a].GetSize()); 628 } 629 630 if(nPointCount > 0x0000ffff) 631 { 632 OSL_FAIL("PolygonFromPolyPolygon: too many points for a single polygon (!)"); 633 nPointCount = 0x0000ffff; 634 } 635 636 tools::Polygon aRetval(static_cast<sal_uInt16>(nPointCount)); 637 sal_uInt32 nAppendIndex(0); 638 639 for(a = 0; a < rPolyPoly.Count(); a++) 640 { 641 const tools::Polygon& rCandidate = rPolyPoly[a]; 642 643 for(sal_uInt16 b(0); nAppendIndex <= nPointCount && b < rCandidate.GetSize(); b++) 644 { 645 aRetval[static_cast<sal_uInt16>(nAppendIndex++)] = rCandidate[b]; 646 } 647 } 648 649 return aRetval; 650 } 651 } 652 CorrectWordWrapPolygonForExport(const tools::PolyPolygon & rPolyPoly,const SwNoTextNode * pNd)653 tools::Polygon CorrectWordWrapPolygonForExport(const tools::PolyPolygon& rPolyPoly, const SwNoTextNode* pNd) 654 { 655 tools::Polygon aPoly(PolygonFromPolyPolygon(rPolyPoly)); 656 const Size &rOrigSize = pNd->GetGraphic().GetPrefSize(); 657 Fraction aMapPolyX(ww::nWrap100Percent, rOrigSize.Width()); 658 Fraction aMapPolyY(ww::nWrap100Percent, rOrigSize.Height()); 659 aPoly.Scale(double(aMapPolyX), double(aMapPolyY)); 660 661 /* 662 a) stretch right bound by 15twips 663 b) shrink bottom bound to where it would have been in word 664 c) Move it to the left by 15twips 665 666 See the import for details 667 */ 668 const Size &rSize = pNd->GetTwipSize(); 669 Fraction aMoveHack(ww::nWrap100Percent, rSize.Width()); 670 aMoveHack *= Fraction(15, 1); 671 long nMove(aMoveHack); 672 673 Fraction aHackX(ww::nWrap100Percent + nMove, 674 ww::nWrap100Percent); 675 Fraction aHackY(ww::nWrap100Percent - nMove, 676 ww::nWrap100Percent); 677 aPoly.Scale(double(aHackX), double(aHackY)); 678 679 aPoly.Move(-nMove, 0); 680 return aPoly; 681 } 682 open(const SwPosition & rPos,const SfxPoolItem & rAttr)683 void RedlineStack::open(const SwPosition& rPos, const SfxPoolItem& rAttr) 684 { 685 OSL_ENSURE(rAttr.Which() == RES_FLTR_REDLINE, "not a redline"); 686 maStack.emplace_back(new SwFltStackEntry(rPos, std::unique_ptr<SfxPoolItem>(rAttr.Clone()))); 687 } 688 689 class SameOpenRedlineType 690 { 691 private: 692 RedlineType const meType; 693 public: SameOpenRedlineType(RedlineType eType)694 explicit SameOpenRedlineType(RedlineType eType) : meType(eType) {} operator ()(const std::unique_ptr<SwFltStackEntry> & pEntry) const695 bool operator()(const std::unique_ptr<SwFltStackEntry> & pEntry) const 696 { 697 const SwFltRedline *pTest = static_cast<const SwFltRedline *> 698 (pEntry->pAttr.get()); 699 return (pEntry->bOpen && (pTest->eType == meType)); 700 } 701 }; 702 close(const SwPosition & rPos,RedlineType eType)703 bool RedlineStack::close(const SwPosition& rPos, RedlineType eType) 704 { 705 //Search from end for same type 706 auto aResult = std::find_if(maStack.rbegin(), maStack.rend(), 707 SameOpenRedlineType(eType)); 708 if (aResult != maStack.rend()) 709 { 710 SwTextNode *const pNode(rPos.nNode.GetNode().GetTextNode()); 711 sal_Int32 const nIndex(rPos.nContent.GetIndex()); 712 // HACK to prevent overlap of field-mark and redline, 713 // which would destroy field-mark invariants when the redline 714 // is hidden: move the redline end one to the left 715 if (pNode && nIndex > 0 716 && pNode->GetText()[nIndex - 1] == CH_TXT_ATR_FIELDEND) 717 { 718 SwPosition const end(*rPos.nNode.GetNode().GetTextNode(), 719 nIndex - 1); 720 sw::mark::IFieldmark *const pFieldMark( 721 rPos.GetDoc()->getIDocumentMarkAccess()->getFieldmarkAt(end)); 722 SAL_WARN_IF(!pFieldMark, "sw.ww8", "expected a field mark"); 723 if (pFieldMark && pFieldMark->GetMarkPos().nNode.GetIndex() == (*aResult)->m_aMkPos.m_nNode.GetIndex()+1 724 && pFieldMark->GetMarkPos().nContent.GetIndex() < (*aResult)->m_aMkPos.m_nContent) 725 { 726 (*aResult)->SetEndPos(end); 727 return true; 728 } 729 } 730 (*aResult)->SetEndPos(rPos); 731 return true; 732 } 733 return false; 734 } 735 closeall(const SwPosition & rPos)736 void RedlineStack::closeall(const SwPosition& rPos) 737 { 738 std::for_each(maStack.begin(), maStack.end(), SetEndIfOpen(rPos)); 739 } 740 MoveAttrs(const SwPosition & rPos,MoveAttrsMode const eMode)741 void RedlineStack::MoveAttrs(const SwPosition& rPos, MoveAttrsMode const eMode) 742 { 743 size_t nCnt = maStack.size(); 744 sal_Int32 const nInserted = eMode == MoveAttrsMode::FieldmarkInserted 745 ? 2 // CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDSEP 746 : 1; 747 sal_uLong nPosNd = rPos.nNode.GetIndex(); 748 sal_Int32 nPosCt = rPos.nContent.GetIndex() - nInserted; 749 750 for (size_t i=0; i < nCnt; ++i) 751 { 752 SwFltStackEntry& rEntry = *maStack[i]; 753 bool const isPoint(rEntry.m_aMkPos == rEntry.m_aPtPos); 754 if ((rEntry.m_aMkPos.m_nNode.GetIndex()+1 == nPosNd) && 755 (nPosCt <= rEntry.m_aMkPos.m_nContent)) 756 { 757 rEntry.m_aMkPos.m_nContent += nInserted; 758 SAL_WARN_IF(rEntry.m_aMkPos.m_nContent > rPos.nNode.GetNodes()[nPosNd]->GetContentNode()->Len(), 759 "sw.ww8", "redline ends after end of line"); 760 if (isPoint) // sigh ... important special case... 761 { 762 rEntry.m_aPtPos.m_nContent += nInserted; 763 continue; 764 } 765 } 766 // for the end position, leave it alone if it's *on* the dummy 767 // char position, that should remain *before* 768 if ((rEntry.m_aPtPos.m_nNode.GetIndex()+1 == nPosNd) && 769 (nPosCt < rEntry.m_aPtPos.m_nContent)) 770 { 771 rEntry.m_aPtPos.m_nContent += nInserted; 772 SAL_WARN_IF(rEntry.m_aPtPos.m_nContent > rPos.nNode.GetNodes()[nPosNd]->GetContentNode()->Len(), 773 "sw.ww8", "redline ends after end of line"); 774 } 775 } 776 } 777 operator ()(std::unique_ptr<SwFltStackEntry> & pEntry)778 void SetInDocAndDelete::operator()(std::unique_ptr<SwFltStackEntry>& pEntry) 779 { 780 SwPaM aRegion(pEntry->m_aMkPos.m_nNode); 781 if (pEntry->MakeRegion(&mrDoc, aRegion, 782 SwFltStackEntry::RegionMode::CheckNodes|SwFltStackEntry::RegionMode::CheckFieldmark) && 783 (*aRegion.GetPoint() != *aRegion.GetMark()) 784 ) 785 { 786 mrDoc.getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | RedlineFlags::ShowInsert | 787 RedlineFlags::ShowDelete); 788 const SwFltRedline *pFltRedline = static_cast<const SwFltRedline*> 789 (pEntry->pAttr.get()); 790 791 SwRedlineData aData(pFltRedline->eType, pFltRedline->nAutorNo, 792 pFltRedline->aStamp, OUString(), nullptr); 793 794 SwRangeRedline *const pNewRedline(new SwRangeRedline(aData, aRegion)); 795 // the point node may be deleted in AppendRedline, so park 796 // the PaM somewhere safe 797 aRegion.DeleteMark(); 798 *aRegion.GetPoint() = SwPosition(SwNodeIndex(mrDoc.GetNodes())); 799 mrDoc.getIDocumentRedlineAccess().AppendRedline(pNewRedline, true); 800 mrDoc.getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::NONE | RedlineFlags::ShowInsert | 801 RedlineFlags::ShowDelete ); 802 } 803 pEntry.reset(); 804 } 805 operator ()(const std::unique_ptr<SwFltStackEntry> & pOneE,const std::unique_ptr<SwFltStackEntry> & pTwoE) const806 bool CompareRedlines::operator()(const std::unique_ptr<SwFltStackEntry> & pOneE, 807 const std::unique_ptr<SwFltStackEntry> & pTwoE) const 808 { 809 const SwFltRedline *pOne= static_cast<const SwFltRedline*> 810 (pOneE->pAttr.get()); 811 const SwFltRedline *pTwo= static_cast<const SwFltRedline*> 812 (pTwoE->pAttr.get()); 813 814 //Return the earlier time, if two have the same time, prioritize 815 //inserts over deletes 816 if (pOne->aStamp == pTwo->aStamp) 817 return (pOne->eType == RedlineType::Insert && pTwo->eType != RedlineType::Insert); 818 else 819 return (pOne->aStamp < pTwo->aStamp); 820 } 821 ~RedlineStack()822 RedlineStack::~RedlineStack() 823 { 824 std::sort(maStack.begin(), maStack.end(), CompareRedlines()); 825 std::for_each(maStack.begin(), maStack.end(), SetInDocAndDelete(mrDoc)); 826 } 827 AddName(const OUString & rNm)828 sal_uInt16 WrtRedlineAuthor::AddName( const OUString& rNm ) 829 { 830 sal_uInt16 nRet; 831 auto aIter = std::find(maAuthors.begin(), maAuthors.end(), rNm); 832 if (aIter != maAuthors.end()) 833 nRet = static_cast< sal_uInt16 >(aIter - maAuthors.begin()); 834 else 835 { 836 nRet = static_cast< sal_uInt16 >(maAuthors.size()); 837 maAuthors.push_back(rNm); 838 } 839 return nRet; 840 } 841 } 842 843 namespace util 844 { InsertedTableListener(SwTableNode & rNode)845 InsertedTableListener::InsertedTableListener(SwTableNode& rNode) 846 : m_pTableNode(&rNode) 847 { 848 StartListening(rNode.GetNotifier()); 849 } 850 GetTableNode()851 SwTableNode* InsertedTableListener::GetTableNode() 852 { return m_pTableNode; } 853 Notify(const SfxHint & rHint)854 void InsertedTableListener::Notify(const SfxHint& rHint) 855 { 856 if(rHint.GetId() == SfxHintId::Dying) 857 m_pTableNode = nullptr; 858 } 859 InsertedTablesManager(const SwDoc & rDoc)860 InsertedTablesManager::InsertedTablesManager(const SwDoc &rDoc) 861 : mbHasRoot(rDoc.getIDocumentLayoutAccess().GetCurrentLayout()) 862 { } 863 DelAndMakeTableFrames()864 void InsertedTablesManager::DelAndMakeTableFrames() 865 { 866 if (!mbHasRoot) 867 return; 868 for (auto& aTable : maTables) 869 { 870 // If already a layout exists, then the BoxFrames must recreated at this table 871 SwTableNode *pTable = aTable.first->GetTableNode(); 872 OSL_ENSURE(pTable, "Why no expected table"); 873 if (pTable) 874 { 875 SwFrameFormat * pFrameFormat = pTable->GetTable().GetFrameFormat(); 876 877 if (pFrameFormat != nullptr) 878 { 879 SwNodeIndex *pIndex = aTable.second; 880 pTable->DelFrames(); 881 pTable->MakeOwnFrames(pIndex); 882 } 883 } 884 } 885 } 886 InsertTable(SwTableNode & rTableNode,SwPaM & rPaM)887 void InsertedTablesManager::InsertTable(SwTableNode& rTableNode, SwPaM& rPaM) 888 { 889 if (!mbHasRoot) 890 return; 891 //Associate this tablenode with this after position, replace an //old 892 //node association if necessary 893 maTables.emplace( 894 std::unique_ptr<InsertedTableListener>(new InsertedTableListener(rTableNode)), 895 &(rPaM.GetPoint()->nNode)); 896 } 897 } 898 899 } 900 901 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 902