android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / layout / layouter.cxx
blob5bed8fcba2b52d5340029c12d0ede4a7192e7a89
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <memory>
21 #include <layouter.hxx>
22 #include <doc.hxx>
23 #include <sectfrm.hxx>
24 #include <pagefrm.hxx>
25 #include <ftnfrm.hxx>
26 #include <txtfrm.hxx>
27 #include <IDocumentLayoutAccess.hxx>
29 #include <movedfwdfrmsbyobjpos.hxx>
30 #include "objstmpconsiderwrapinfl.hxx"
31 #include <osl/diagnose.h>
33 #define LOOP_DETECT 250
35 class SwLooping
37 sal_uInt16 mnMinPage;
38 sal_uInt16 mnMaxPage;
39 sal_uInt16 mnCount;
40 sal_uInt16 mnLoopControlStage;
41 public:
42 explicit SwLooping( SwPageFrame const * pPage );
43 void Control( SwPageFrame* pPage );
44 void Drastic( SwFrame* pFrame );
45 bool IsLoopingLouieLight() const { return mnCount > LOOP_DETECT - 30; };
48 class SwEndnoter
50 SwLayouter* m_pMaster;
51 SwSectionFrame* m_pSect;
52 std::unique_ptr<SwFootnoteFrames> m_pEndArr;
53 public:
54 explicit SwEndnoter( SwLayouter* pLay )
55 : m_pMaster( pLay ), m_pSect( nullptr ) {}
56 void CollectEndnotes( SwSectionFrame* pSct );
57 void CollectEndnote( SwFootnoteFrame* pFootnote );
58 const SwSectionFrame* GetSect() const { return m_pSect; }
59 void InsertEndnotes();
60 bool HasEndnotes() const { return m_pEndArr && !m_pEndArr->empty(); }
63 void SwEndnoter::CollectEndnotes( SwSectionFrame* pSct )
65 OSL_ENSURE( pSct, "CollectEndnotes: Which section?" );
66 if( !m_pSect )
67 m_pSect = pSct;
68 else if( pSct != m_pSect )
69 return;
70 m_pSect->CollectEndnotes( m_pMaster );
73 void SwEndnoter::CollectEndnote( SwFootnoteFrame* pFootnote )
75 if( m_pEndArr && m_pEndArr->end() != std::find( m_pEndArr->begin(), m_pEndArr->end(), pFootnote ) )
76 return;
78 if( pFootnote->GetUpper() )
80 // pFootnote is the master, he incorporates its follows
81 SwFootnoteFrame *pNxt = pFootnote->GetFollow();
82 while ( pNxt )
84 SwFrame *pCnt = pNxt->ContainsAny();
85 if ( pCnt )
88 { SwFrame *pNxtCnt = pCnt->GetNext();
89 pCnt->Cut();
90 pCnt->Paste( pFootnote );
91 pCnt = pNxtCnt;
92 } while ( pCnt );
94 else
96 OSL_ENSURE( pNxt->Lower() && pNxt->Lower()->IsSctFrame(),
97 "Endnote without content?" );
98 pNxt->Cut();
99 SwFrame::DestroyFrame(pNxt);
101 pNxt = pFootnote->GetFollow();
103 if( pFootnote->GetMaster() )
104 return;
105 pFootnote->Cut();
107 else if( m_pEndArr )
109 for (SwFootnoteFrame* pEndFootnote : *m_pEndArr)
111 if( pEndFootnote->GetAttr() == pFootnote->GetAttr() )
113 SwFrame::DestroyFrame(pFootnote);
114 return;
118 if( !m_pEndArr )
119 m_pEndArr.reset( new SwFootnoteFrames ); // deleted from the SwLayouter
120 m_pEndArr->push_back( pFootnote );
123 void SwEndnoter::InsertEndnotes()
125 if( !m_pSect )
126 return;
127 if( !m_pEndArr || m_pEndArr->empty() )
129 m_pSect = nullptr;
130 return;
132 OSL_ENSURE( m_pSect->Lower() && m_pSect->Lower()->IsFootnoteBossFrame(),
133 "InsertEndnotes: Where's my column?" );
134 SwFrame* pRef = m_pSect->FindLastContent( SwFindMode::MyLast );
135 SwFootnoteBossFrame *pBoss = pRef ? pRef->FindFootnoteBossFrame()
136 : static_cast<SwFootnoteBossFrame*>(m_pSect->Lower());
137 pBoss->MoveFootnotes_( *m_pEndArr );
138 m_pEndArr.reset();
139 m_pSect = nullptr;
142 SwLooping::SwLooping( SwPageFrame const * pPage )
144 assert(pPage);
145 mnMinPage = pPage->GetPhyPageNum();
146 mnMaxPage = mnMinPage;
147 mnCount = 0;
148 mnLoopControlStage = 0;
151 void SwLooping::Drastic( SwFrame* pFrame )
153 while( pFrame )
155 pFrame->ValidateThisAndAllLowers( mnLoopControlStage );
156 pFrame = pFrame->GetNext();
160 void SwLooping::Control( SwPageFrame* pPage )
162 if( !pPage )
163 return;
164 const sal_uInt16 nNew = pPage->GetPhyPageNum();
165 if (nNew > mnMaxPage)
166 mnMaxPage = nNew;
167 if (nNew < mnMinPage)
169 mnMinPage = nNew;
170 mnMaxPage = nNew;
171 mnCount = 0;
172 mnLoopControlStage = 0;
174 else if (nNew > mnMinPage + 2)
176 mnMinPage = nNew - 2;
177 mnMaxPage = nNew;
178 mnCount = 0;
179 mnLoopControlStage = 0;
181 else if (++mnCount > LOOP_DETECT)
183 #if OSL_DEBUG_LEVEL > 1
184 static bool bNoLouie = false;
185 if( bNoLouie )
186 return;
187 #endif
189 // FME 2007-08-30 #i81146# new loop control
190 SAL_WARN("sw.layout", "Looping Louie: Stage " << (mnLoopControlStage + 1) << "!");
192 Drastic( pPage->Lower() );
193 if (nNew > mnMinPage && pPage->GetPrev())
194 Drastic( static_cast<SwPageFrame*>(pPage->GetPrev())->Lower() );
195 if (nNew < mnMaxPage && pPage->GetNext())
196 Drastic( static_cast<SwPageFrame*>(pPage->GetNext())->Lower() );
198 ++mnLoopControlStage;
199 mnCount = 0;
203 SwLayouter::SwLayouter()
207 SwLayouter::~SwLayouter()
211 void SwLayouter::CollectEndnotes_( SwSectionFrame* pSect )
213 if( !mpEndnoter )
214 mpEndnoter.reset(new SwEndnoter( this ));
215 mpEndnoter->CollectEndnotes( pSect );
218 bool SwLayouter::HasEndnotes() const
220 return mpEndnoter->HasEndnotes();
223 void SwLayouter::CollectEndnote( SwFootnoteFrame* pFootnote )
225 mpEndnoter->CollectEndnote( pFootnote );
228 void SwLayouter::InsertEndnotes( SwSectionFrame const * pSect )
230 if( !mpEndnoter || mpEndnoter->GetSect() != pSect )
231 return;
232 mpEndnoter->InsertEndnotes();
235 void SwLayouter::LoopControl( SwPageFrame* pPage )
237 assert(mpLooping);
238 mpLooping->Control( pPage );
241 void SwLayouter::LoopingLouieLight( const SwDoc& rDoc, const SwTextFrame& rFrame )
243 if ( mpLooping && mpLooping->IsLoopingLouieLight() )
245 SAL_WARN("sw.layout", "Looping Louie (Light): Fixating fractious frame");
246 SwLayouter::InsertMovedFwdFrame( rDoc, rFrame, rFrame.FindPageFrame()->GetPhyPageNum() );
250 bool SwLayouter::StartLooping( SwPageFrame const * pPage )
252 if( mpLooping )
253 return false;
254 mpLooping.reset(new SwLooping( pPage ));
255 return true;
258 void SwLayouter::EndLoopControl()
260 mpLooping.reset();
263 void SwLayouter::CollectEndnotes( SwDoc* pDoc, SwSectionFrame* pSect )
265 assert(pDoc && "No doc, no fun");
266 if( !pDoc->getIDocumentLayoutAccess().GetLayouter() )
267 pDoc->getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
268 pDoc->getIDocumentLayoutAccess().GetLayouter()->CollectEndnotes_( pSect );
271 bool SwLayouter::Collecting( SwDoc* pDoc, SwSectionFrame const * pSect, SwFootnoteFrame* pFootnote )
273 if( !pDoc->getIDocumentLayoutAccess().GetLayouter() )
274 return false;
275 SwLayouter *pLayouter = pDoc->getIDocumentLayoutAccess().GetLayouter();
276 if( pLayouter->mpEndnoter && pLayouter->mpEndnoter->GetSect() && pSect &&
277 ( pLayouter->mpEndnoter->GetSect()->IsAnFollow( pSect ) ||
278 pSect->IsAnFollow( pLayouter->mpEndnoter->GetSect() ) ) )
280 if( pFootnote )
281 pLayouter->CollectEndnote( pFootnote );
282 return true;
284 return false;
287 bool SwLayouter::StartLoopControl( SwDoc* pDoc, SwPageFrame const *pPage )
289 assert(pDoc);
290 if( !pDoc->getIDocumentLayoutAccess().GetLayouter() )
291 pDoc->getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
292 return !pDoc->getIDocumentLayoutAccess().GetLayouter()->mpLooping &&
293 pDoc->getIDocumentLayoutAccess().GetLayouter()->StartLooping( pPage );
296 // #i28701#
297 // methods to manage text frames, which are moved forward by the positioning
298 // of its anchored objects
299 void SwLayouter::ClearMovedFwdFrames( const SwDoc& _rDoc )
301 if ( _rDoc.getIDocumentLayoutAccess().GetLayouter() &&
302 _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames )
304 _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames->Clear();
308 void SwLayouter::InsertMovedFwdFrame( const SwDoc& _rDoc,
309 const SwTextFrame& _rMovedFwdFrameByObjPos,
310 const sal_uInt32 _nToPageNum )
312 if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() )
314 const_cast<SwDoc&>(_rDoc).getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
317 if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames )
319 const_cast<SwDoc&>(_rDoc).getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames.reset(
320 new SwMovedFwdFramesByObjPos());
323 _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames->Insert( _rMovedFwdFrameByObjPos,
324 _nToPageNum );
327 // #i40155#
328 void SwLayouter::RemoveMovedFwdFrame( const SwDoc& _rDoc,
329 const SwTextFrame& _rTextFrame )
331 sal_uInt32 nDummy;
332 if ( SwLayouter::FrameMovedFwdByObjPos( _rDoc, _rTextFrame, nDummy ) )
334 _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames->Remove( _rTextFrame );
338 bool SwLayouter::FrameMovedFwdByObjPos( const SwDoc& _rDoc,
339 const SwTextFrame& _rTextFrame,
340 sal_uInt32& _ornToPageNum )
342 if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() )
344 _ornToPageNum = 0;
345 return false;
347 else if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames )
349 _ornToPageNum = 0;
350 return false;
352 else
354 return _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames->
355 FrameMovedFwdByObjPos( _rTextFrame, _ornToPageNum );
359 // #i26945#
360 bool SwLayouter::DoesRowContainMovedFwdFrame( const SwDoc& _rDoc,
361 const SwRowFrame& _rRowFrame )
363 if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() )
365 return false;
367 else if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames )
369 return false;
371 else
373 return _rDoc.getIDocumentLayoutAccess().GetLayouter()->
374 mpMovedFwdFrames->DoesRowContainMovedFwdFrame( _rRowFrame );
378 // #i35911#
379 void SwLayouter::ClearObjsTmpConsiderWrapInfluence( const SwDoc& _rDoc )
381 if ( _rDoc.getIDocumentLayoutAccess().GetLayouter() &&
382 _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl )
384 _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl->Clear();
388 void SwLayouter::InsertObjForTmpConsiderWrapInfluence(
389 const SwDoc& _rDoc,
390 SwAnchoredObject& _rAnchoredObj )
392 if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() )
394 const_cast<SwDoc&>(_rDoc).getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
397 if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl )
399 const_cast<SwDoc&>(_rDoc).getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl.reset(
400 new SwObjsMarkedAsTmpConsiderWrapInfluence());
403 _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl->Insert( _rAnchoredObj );
406 void SwLayouter::RemoveObjForTmpConsiderWrapInfluence(
407 const SwDoc& _rDoc,
408 SwAnchoredObject& _rAnchoredObj )
410 if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() )
411 return;
413 if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl )
414 return;
416 _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl->Remove( _rAnchoredObj );
420 void LOOPING_LOUIE_LIGHT( bool bCondition, const SwTextFrame& rTextFrame )
422 if ( bCondition )
424 const SwDoc& rDoc = *rTextFrame.GetAttrSet()->GetDoc();
425 if ( rDoc.getIDocumentLayoutAccess().GetLayouter() )
427 const_cast<SwDoc&>(rDoc).getIDocumentLayoutAccess().GetLayouter()->LoopingLouieLight( rDoc, rTextFrame );
432 // #i65250#
433 bool SwLayouter::MoveBwdSuppressed( const SwDoc& p_rDoc,
434 const SwFlowFrame& p_rFlowFrame,
435 const SwLayoutFrame& p_rNewUpperFrame )
437 bool bMoveBwdSuppressed( false );
439 if ( !p_rDoc.getIDocumentLayoutAccess().GetLayouter() )
441 const_cast<SwDoc&>(p_rDoc).getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
444 // create hash map key
445 tMoveBwdLayoutInfoKey aMoveBwdLayoutInfo;
446 aMoveBwdLayoutInfo.mnFrameId = p_rFlowFrame.GetFrame().GetFrameId();
447 aMoveBwdLayoutInfo.mnNewUpperPosX = p_rNewUpperFrame.getFrameArea().Pos().X();
448 aMoveBwdLayoutInfo.mnNewUpperPosY = p_rNewUpperFrame.getFrameArea().Pos().Y();
449 aMoveBwdLayoutInfo.mnNewUpperWidth = p_rNewUpperFrame.getFrameArea().Width();
450 aMoveBwdLayoutInfo.mnNewUpperHeight = p_rNewUpperFrame.getFrameArea().Height();
451 SwRectFnSet aRectFnSet(&p_rNewUpperFrame);
452 const SwFrame* pLastLower( p_rNewUpperFrame.Lower() );
453 while ( pLastLower && pLastLower->GetNext() )
455 pLastLower = pLastLower->GetNext();
457 aMoveBwdLayoutInfo.mnFreeSpaceInNewUpper =
458 pLastLower
459 ? aRectFnSet.BottomDist( pLastLower->getFrameArea(), aRectFnSet.GetPrtBottom(p_rNewUpperFrame) )
460 : aRectFnSet.GetHeight(p_rNewUpperFrame.getFrameArea());
462 // check for moving backward suppress threshold
463 const sal_uInt16 cMoveBwdCountSuppressThreshold = 20;
464 if ( ++const_cast<SwDoc&>(p_rDoc).getIDocumentLayoutAccess().GetLayouter()->maMoveBwdLayoutInfo[ aMoveBwdLayoutInfo ] >
465 cMoveBwdCountSuppressThreshold )
467 bMoveBwdSuppressed = true;
470 return bMoveBwdSuppressed;
473 void SwLayouter::ClearMoveBwdLayoutInfo( const SwDoc& _rDoc )
475 if ( _rDoc.getIDocumentLayoutAccess().GetLayouter() )
476 const_cast<SwDoc&>(_rDoc).getIDocumentLayoutAccess().GetLayouter()->maMoveBwdLayoutInfo.clear();
479 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */