/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include "layouter.hxx" #include "doc.hxx" #include "sectfrm.hxx" #include "pagefrm.hxx" #include "ftnfrm.hxx" #include "txtfrm.hxx" #include #include #include #define LOOP_DETECT 250 class SwLooping { sal_uInt16 nMinPage; sal_uInt16 nMaxPage; sal_uInt16 nCount; sal_uInt16 mnLoopControlStage; public: explicit SwLooping( SwPageFrame* pPage ); void Control( SwPageFrame* pPage ); void Drastic( SwFrame* pFrame ); bool IsLoopingLouieLight() const { return nCount > LOOP_DETECT - 30; }; }; class SwEndnoter { SwLayouter* pMaster; SwSectionFrame* pSect; SwFootnoteFrames* pEndArr; public: explicit SwEndnoter( SwLayouter* pLay ) : pMaster( pLay ), pSect( nullptr ), pEndArr( nullptr ) {} ~SwEndnoter() { delete pEndArr; } void CollectEndnotes( SwSectionFrame* pSct ); void CollectEndnote( SwFootnoteFrame* pFootnote ); const SwSectionFrame* GetSect() const { return pSect; } void InsertEndnotes(); bool HasEndnotes() const { return pEndArr && !pEndArr->empty(); } }; void SwEndnoter::CollectEndnotes( SwSectionFrame* pSct ) { OSL_ENSURE( pSct, "CollectEndnotes: Which section?" ); if( !pSect ) pSect = pSct; else if( pSct != pSect ) return; pSect->CollectEndnotes( pMaster ); } void SwEndnoter::CollectEndnote( SwFootnoteFrame* pFootnote ) { if( pEndArr && pEndArr->end() != std::find( pEndArr->begin(), pEndArr->end(), pFootnote ) ) return; if( pFootnote->GetUpper() ) { // pFootnote is the master, he incorporates its follows SwFootnoteFrame *pNxt = pFootnote->GetFollow(); while ( pNxt ) { SwFrame *pCnt = pNxt->ContainsAny(); if ( pCnt ) { do { SwFrame *pNxtCnt = pCnt->GetNext(); pCnt->Cut(); pCnt->Paste( pFootnote ); pCnt = pNxtCnt; } while ( pCnt ); } else { OSL_ENSURE( pNxt->Lower() && pNxt->Lower()->IsSctFrame(), "Endnote without content?" ); pNxt->Cut(); SwFrame::DestroyFrame(pNxt); } pNxt = pFootnote->GetFollow(); } if( pFootnote->GetMaster() ) return; pFootnote->Cut(); } else if( pEndArr ) { for ( size_t i = 0; i < pEndArr->size(); ++i ) { SwFootnoteFrame *pEndFootnote = (*pEndArr)[i]; if( pEndFootnote->GetAttr() == pFootnote->GetAttr() ) { SwFrame::DestroyFrame(pFootnote); return; } } } if( !pEndArr ) pEndArr = new SwFootnoteFrames; // deleted from the SwLayouter pEndArr->push_back( pFootnote ); } void SwEndnoter::InsertEndnotes() { if( !pSect ) return; if( !pEndArr || pEndArr->empty() ) { pSect = nullptr; return; } OSL_ENSURE( pSect->Lower() && pSect->Lower()->IsFootnoteBossFrame(), "InsertEndnotes: Where's my column?" ); SwFrame* pRef = pSect->FindLastContent( FINDMODE_MYLAST ); SwFootnoteBossFrame *pBoss = pRef ? pRef->FindFootnoteBossFrame() : static_cast(pSect->Lower()); pBoss->_MoveFootnotes( *pEndArr ); delete pEndArr; pEndArr = nullptr; pSect = nullptr; } SwLooping::SwLooping( SwPageFrame* pPage ) { OSL_ENSURE( pPage, "Where's my page?" ); nMinPage = pPage->GetPhyPageNum(); nMaxPage = nMinPage; nCount = 0; mnLoopControlStage = 0; } void SwLooping::Drastic( SwFrame* pFrame ) { while( pFrame ) { pFrame->ValidateThisAndAllLowers( mnLoopControlStage ); pFrame = pFrame->GetNext(); } } void SwLooping::Control( SwPageFrame* pPage ) { if( !pPage ) return; const sal_uInt16 nNew = pPage->GetPhyPageNum(); if( nNew > nMaxPage ) nMaxPage = nNew; if( nNew < nMinPage ) { nMinPage = nNew; nMaxPage = nNew; nCount = 0; mnLoopControlStage = 0; } else if( nNew > nMinPage + 2 ) { nMinPage = nNew - 2; nMaxPage = nNew; nCount = 0; mnLoopControlStage = 0; } else if( ++nCount > LOOP_DETECT ) { #if OSL_DEBUG_LEVEL > 1 static bool bNoLouie = false; if( bNoLouie ) return; // FME 2007-08-30 #i81146# new loop control OSL_ENSURE( 0 != mnLoopControlStage, "Looping Louie: Stage 1!" ); OSL_ENSURE( 1 != mnLoopControlStage, "Looping Louie: Stage 2!!" ); OSL_ENSURE( 2 > mnLoopControlStage, "Looping Louie: Stage 3!!!" ); #endif Drastic( pPage->Lower() ); if( nNew > nMinPage && pPage->GetPrev() ) Drastic( static_cast(pPage->GetPrev())->Lower() ); if( nNew < nMaxPage && pPage->GetNext() ) Drastic( static_cast(pPage->GetNext())->Lower() ); ++mnLoopControlStage; nCount = 0; } } SwLayouter::SwLayouter() : mpEndnoter( nullptr ), mpLooping( nullptr ), // #i28701# mpMovedFwdFrames( nullptr ), // #i35911# mpObjsTmpConsiderWrapInfl( nullptr ) { } SwLayouter::~SwLayouter() { delete mpEndnoter; delete mpLooping; // #i28701# delete mpMovedFwdFrames; mpMovedFwdFrames = nullptr; // #i35911# delete mpObjsTmpConsiderWrapInfl; mpObjsTmpConsiderWrapInfl = nullptr; } void SwLayouter::_CollectEndnotes( SwSectionFrame* pSect ) { if( !mpEndnoter ) mpEndnoter = new SwEndnoter( this ); mpEndnoter->CollectEndnotes( pSect ); } bool SwLayouter::HasEndnotes() const { return mpEndnoter->HasEndnotes(); } void SwLayouter::CollectEndnote( SwFootnoteFrame* pFootnote ) { mpEndnoter->CollectEndnote( pFootnote ); } void SwLayouter::InsertEndnotes( SwSectionFrame* pSect ) { if( !mpEndnoter || mpEndnoter->GetSect() != pSect ) return; mpEndnoter->InsertEndnotes(); } void SwLayouter::LoopControl( SwPageFrame* pPage, sal_uInt8 ) { OSL_ENSURE( mpLooping, "Looping: Lost control" ); mpLooping->Control( pPage ); } void SwLayouter::LoopingLouieLight( const SwDoc& rDoc, const SwTextFrame& rFrame ) { if ( mpLooping && mpLooping->IsLoopingLouieLight() ) { #if OSL_DEBUG_LEVEL > 1 OSL_FAIL( "Looping Louie (Light): Fixating fractious frame" ); #endif SwLayouter::InsertMovedFwdFrame( rDoc, rFrame, rFrame.FindPageFrame()->GetPhyPageNum() ); } } bool SwLayouter::StartLooping( SwPageFrame* pPage ) { if( mpLooping ) return false; mpLooping = new SwLooping( pPage ); return true; } void SwLayouter::EndLoopControl() { delete mpLooping; mpLooping = nullptr; } void SwLayouter::CollectEndnotes( SwDoc* pDoc, SwSectionFrame* pSect ) { assert(pDoc && "No doc, no fun"); if( !pDoc->getIDocumentLayoutAccess().GetLayouter() ) pDoc->getIDocumentLayoutAccess().SetLayouter( new SwLayouter() ); pDoc->getIDocumentLayoutAccess().GetLayouter()->_CollectEndnotes( pSect ); } bool SwLayouter::Collecting( SwDoc* pDoc, SwSectionFrame* pSect, SwFootnoteFrame* pFootnote ) { if( !pDoc->getIDocumentLayoutAccess().GetLayouter() ) return false; SwLayouter *pLayouter = pDoc->getIDocumentLayoutAccess().GetLayouter(); if( pLayouter->mpEndnoter && pLayouter->mpEndnoter->GetSect() && pSect && ( pLayouter->mpEndnoter->GetSect()->IsAnFollow( pSect ) || pSect->IsAnFollow( pLayouter->mpEndnoter->GetSect() ) ) ) { if( pFootnote ) pLayouter->CollectEndnote( pFootnote ); return true; } return false; } bool SwLayouter::StartLoopControl( SwDoc* pDoc, SwPageFrame *pPage ) { OSL_ENSURE( pDoc, "No doc, no fun" ); if( !pDoc->getIDocumentLayoutAccess().GetLayouter() ) pDoc->getIDocumentLayoutAccess().SetLayouter( new SwLayouter() ); return !pDoc->getIDocumentLayoutAccess().GetLayouter()->mpLooping && pDoc->getIDocumentLayoutAccess().GetLayouter()->StartLooping( pPage ); } // #i28701# // methods to manage text frames, which are moved forward by the positioning // of its anchored objects void SwLayouter::ClearMovedFwdFrames( const SwDoc& _rDoc ) { if ( _rDoc.getIDocumentLayoutAccess().GetLayouter() && _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames ) { _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames->Clear(); } } void SwLayouter::InsertMovedFwdFrame( const SwDoc& _rDoc, const SwTextFrame& _rMovedFwdFrameByObjPos, const sal_uInt32 _nToPageNum ) { if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() ) { const_cast(_rDoc).getIDocumentLayoutAccess().SetLayouter( new SwLayouter() ); } if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames ) { const_cast(_rDoc).getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames = new SwMovedFwdFramesByObjPos(); } _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames->Insert( _rMovedFwdFrameByObjPos, _nToPageNum ); } // #i40155# void SwLayouter::RemoveMovedFwdFrame( const SwDoc& _rDoc, const SwTextFrame& _rTextFrame ) { sal_uInt32 nDummy; if ( SwLayouter::FrameMovedFwdByObjPos( _rDoc, _rTextFrame, nDummy ) ) { _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames->Remove( _rTextFrame ); } } bool SwLayouter::FrameMovedFwdByObjPos( const SwDoc& _rDoc, const SwTextFrame& _rTextFrame, sal_uInt32& _ornToPageNum ) { if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() ) { _ornToPageNum = 0; return false; } else if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames ) { _ornToPageNum = 0; return false; } else { return _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames-> FrameMovedFwdByObjPos( _rTextFrame, _ornToPageNum ); } } // #i26945# bool SwLayouter::DoesRowContainMovedFwdFrame( const SwDoc& _rDoc, const SwRowFrame& _rRowFrame ) { if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() ) { return false; } else if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames ) { return false; } else { return _rDoc.getIDocumentLayoutAccess().GetLayouter()-> mpMovedFwdFrames->DoesRowContainMovedFwdFrame( _rRowFrame ); } } // #i35911# void SwLayouter::ClearObjsTmpConsiderWrapInfluence( const SwDoc& _rDoc ) { if ( _rDoc.getIDocumentLayoutAccess().GetLayouter() && _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl ) { _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl->Clear(); } } void SwLayouter::InsertObjForTmpConsiderWrapInfluence( const SwDoc& _rDoc, SwAnchoredObject& _rAnchoredObj ) { if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() ) { const_cast(_rDoc).getIDocumentLayoutAccess().SetLayouter( new SwLayouter() ); } if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl ) { const_cast(_rDoc).getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl = new SwObjsMarkedAsTmpConsiderWrapInfluence(); } _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl->Insert( _rAnchoredObj ); } void LOOPING_LOUIE_LIGHT( bool bCondition, const SwTextFrame& rTextFrame ) { if ( bCondition ) { const SwDoc& rDoc = *rTextFrame.GetAttrSet()->GetDoc(); if ( rDoc.getIDocumentLayoutAccess().GetLayouter() ) { const_cast(rDoc).getIDocumentLayoutAccess().GetLayouter()->LoopingLouieLight( rDoc, rTextFrame ); } } } // #i65250# bool SwLayouter::MoveBwdSuppressed( const SwDoc& p_rDoc, const SwFlowFrame& p_rFlowFrame, const SwLayoutFrame& p_rNewUpperFrame ) { bool bMoveBwdSuppressed( false ); if ( !p_rDoc.getIDocumentLayoutAccess().GetLayouter() ) { const_cast(p_rDoc).getIDocumentLayoutAccess().SetLayouter( new SwLayouter() ); } // create hash map key tMoveBwdLayoutInfoKey aMoveBwdLayoutInfo; aMoveBwdLayoutInfo.mnFrameId = p_rFlowFrame.GetFrame().GetFrameId(); aMoveBwdLayoutInfo.mnNewUpperPosX = p_rNewUpperFrame.Frame().Pos().X(); aMoveBwdLayoutInfo.mnNewUpperPosY = p_rNewUpperFrame.Frame().Pos().Y(); aMoveBwdLayoutInfo.mnNewUpperWidth = p_rNewUpperFrame.Frame().Width(); aMoveBwdLayoutInfo.mnNewUpperHeight = p_rNewUpperFrame.Frame().Height(); SWRECTFN( (&p_rNewUpperFrame) ) const SwFrame* pLastLower( p_rNewUpperFrame.Lower() ); while ( pLastLower && pLastLower->GetNext() ) { pLastLower = pLastLower->GetNext(); } aMoveBwdLayoutInfo.mnFreeSpaceInNewUpper = pLastLower ? (pLastLower->Frame().*fnRect->fnBottomDist)( (p_rNewUpperFrame.*fnRect->fnGetPrtBottom)() ) : (p_rNewUpperFrame.Frame().*fnRect->fnGetHeight)(); // check for moving backward suppress threshold const sal_uInt16 cMoveBwdCountSuppressThreshold = 20; if ( ++const_cast(p_rDoc).getIDocumentLayoutAccess().GetLayouter()->maMoveBwdLayoutInfo[ aMoveBwdLayoutInfo ] > cMoveBwdCountSuppressThreshold ) { bMoveBwdSuppressed = true; } return bMoveBwdSuppressed; } void SwLayouter::ClearMoveBwdLayoutInfo( const SwDoc& _rDoc ) { if ( _rDoc.getIDocumentLayoutAccess().GetLayouter() ) const_cast(_rDoc).getIDocumentLayoutAccess().GetLayouter()->maMoveBwdLayoutInfo.clear(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */