1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
21 #include <layouter.hxx>
23 #include <sectfrm.hxx>
24 #include <pagefrm.hxx>
27 #include <IDocumentLayoutAccess.hxx>
29 #include <movedfwdfrmsbyobjpos.hxx>
30 #include "objstmpconsiderwrapinfl.hxx"
31 #include <osl/diagnose.h>
33 #define LOOP_DETECT 250
40 sal_uInt16 mnLoopControlStage
;
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; };
50 SwLayouter
* m_pMaster
;
51 SwSectionFrame
* m_pSect
;
52 std::unique_ptr
<SwFootnoteFrames
> m_pEndArr
;
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?" );
68 else if( pSct
!= m_pSect
)
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
) )
78 if( pFootnote
->GetUpper() )
80 // pFootnote is the master, he incorporates its follows
81 SwFootnoteFrame
*pNxt
= pFootnote
->GetFollow();
84 SwFrame
*pCnt
= pNxt
->ContainsAny();
88 { SwFrame
*pNxtCnt
= pCnt
->GetNext();
90 pCnt
->Paste( pFootnote
);
97 SwFrame
* pLower
= pNxt
->Lower();
98 OSL_ENSURE( pLower
&& pLower
->IsSctFrame(),
99 "Endnote without content?" );
102 SwFrame::DestroyFrame(pNxt
);
104 pNxt
= pFootnote
->GetFollow();
106 if( pFootnote
->GetMaster() )
112 for (SwFootnoteFrame
* pEndFootnote
: *m_pEndArr
)
114 if( pEndFootnote
->GetAttr() == pFootnote
->GetAttr() )
116 SwFrame::DestroyFrame(pFootnote
);
122 m_pEndArr
.reset( new SwFootnoteFrames
); // deleted from the SwLayouter
123 m_pEndArr
->push_back( pFootnote
);
126 void SwEndnoter::InsertEndnotes()
130 if( !m_pEndArr
|| m_pEndArr
->empty() )
135 SwFrame
* pLower
= m_pSect
->Lower();
136 OSL_ENSURE( pLower
&& pLower
->IsFootnoteBossFrame(),
137 "InsertEndnotes: Where's my column?" );
138 SwFrame
* pRef
= m_pSect
->FindLastContent( SwFindMode::MyLast
);
139 SwFootnoteBossFrame
*pBoss
= pRef
? pRef
->FindFootnoteBossFrame()
140 : static_cast<SwFootnoteBossFrame
*>(pLower
);
141 pBoss
->MoveFootnotes_( *m_pEndArr
);
146 SwLooping::SwLooping( SwPageFrame
const * pPage
)
149 mnMinPage
= pPage
->GetPhyPageNum();
150 mnMaxPage
= mnMinPage
;
152 mnLoopControlStage
= 0;
155 void SwLooping::Drastic( SwFrame
* pFrame
)
159 pFrame
->ValidateThisAndAllLowers( mnLoopControlStage
);
160 pFrame
= pFrame
->GetNext();
164 void SwLooping::Control( SwPageFrame
* pPage
)
168 const sal_uInt16 nNew
= pPage
->GetPhyPageNum();
169 if (nNew
> mnMaxPage
)
171 if (nNew
< mnMinPage
)
176 mnLoopControlStage
= 0;
178 else if (nNew
> mnMinPage
+ 2)
180 mnMinPage
= nNew
- 2;
183 mnLoopControlStage
= 0;
185 else if (++mnCount
> LOOP_DETECT
)
187 #if OSL_DEBUG_LEVEL > 1
188 static bool bNoLouie
= false;
193 // FME 2007-08-30 #i81146# new loop control
194 SAL_WARN("sw.layout", "Looping Louie: Stage " << (mnLoopControlStage
+ 1) << "!");
196 Drastic( pPage
->Lower() );
197 if (nNew
> mnMinPage
&& pPage
->GetPrev())
198 Drastic( static_cast<SwPageFrame
*>(pPage
->GetPrev())->Lower() );
199 if (nNew
< mnMaxPage
&& pPage
->GetNext())
200 Drastic( static_cast<SwPageFrame
*>(pPage
->GetNext())->Lower() );
202 ++mnLoopControlStage
;
207 SwLayouter::SwLayouter()
211 SwLayouter::~SwLayouter()
215 void SwLayouter::CollectEndnotes_( SwSectionFrame
* pSect
)
218 mpEndnoter
.reset(new SwEndnoter( this ));
219 mpEndnoter
->CollectEndnotes( pSect
);
222 bool SwLayouter::HasEndnotes() const
224 return mpEndnoter
->HasEndnotes();
227 void SwLayouter::CollectEndnote( SwFootnoteFrame
* pFootnote
)
229 mpEndnoter
->CollectEndnote( pFootnote
);
232 void SwLayouter::InsertEndnotes( SwSectionFrame
const * pSect
)
234 if( !mpEndnoter
|| mpEndnoter
->GetSect() != pSect
)
236 mpEndnoter
->InsertEndnotes();
239 void SwLayouter::LoopControl( SwPageFrame
* pPage
)
242 mpLooping
->Control( pPage
);
245 void SwLayouter::LoopingLouieLight( const SwDoc
& rDoc
, const SwTextFrame
& rFrame
)
247 if ( mpLooping
&& mpLooping
->IsLoopingLouieLight() )
249 SAL_WARN("sw.layout", "Looping Louie (Light): Fixating fractious frame");
250 SwLayouter::InsertMovedFwdFrame( rDoc
, rFrame
, rFrame
.FindPageFrame()->GetPhyPageNum() );
254 bool SwLayouter::StartLooping( SwPageFrame
const * pPage
)
258 mpLooping
.reset(new SwLooping( pPage
));
262 void SwLayouter::EndLoopControl()
267 void SwLayouter::CollectEndnotes( SwDoc
* pDoc
, SwSectionFrame
* pSect
)
269 assert(pDoc
&& "No doc, no fun");
270 if( !pDoc
->getIDocumentLayoutAccess().GetLayouter() )
271 pDoc
->getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
272 pDoc
->getIDocumentLayoutAccess().GetLayouter()->CollectEndnotes_( pSect
);
275 bool SwLayouter::Collecting( SwDoc
* pDoc
, SwSectionFrame
const * pSect
, SwFootnoteFrame
* pFootnote
)
277 if( !pDoc
->getIDocumentLayoutAccess().GetLayouter() )
279 SwLayouter
*pLayouter
= pDoc
->getIDocumentLayoutAccess().GetLayouter();
280 if( pLayouter
->mpEndnoter
&& pLayouter
->mpEndnoter
->GetSect() && pSect
&&
281 ( pLayouter
->mpEndnoter
->GetSect()->IsAnFollow( pSect
) ||
282 pSect
->IsAnFollow( pLayouter
->mpEndnoter
->GetSect() ) ) )
285 pLayouter
->CollectEndnote( pFootnote
);
291 bool SwLayouter::StartLoopControl( SwDoc
* pDoc
, SwPageFrame
const *pPage
)
294 if( !pDoc
->getIDocumentLayoutAccess().GetLayouter() )
295 pDoc
->getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
296 return !pDoc
->getIDocumentLayoutAccess().GetLayouter()->mpLooping
&&
297 pDoc
->getIDocumentLayoutAccess().GetLayouter()->StartLooping( pPage
);
301 // methods to manage text frames, which are moved forward by the positioning
302 // of its anchored objects
303 void SwLayouter::ClearMovedFwdFrames( const SwDoc
& _rDoc
)
305 if ( _rDoc
.getIDocumentLayoutAccess().GetLayouter() &&
306 _rDoc
.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames
)
308 _rDoc
.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames
->Clear();
312 void SwLayouter::InsertMovedFwdFrame( const SwDoc
& _rDoc
,
313 const SwTextFrame
& _rMovedFwdFrameByObjPos
,
314 const sal_uInt32 _nToPageNum
)
316 if ( !_rDoc
.getIDocumentLayoutAccess().GetLayouter() )
318 const_cast<SwDoc
&>(_rDoc
).getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
321 if ( !_rDoc
.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames
)
323 const_cast<SwDoc
&>(_rDoc
).getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames
.reset(
324 new SwMovedFwdFramesByObjPos());
327 _rDoc
.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames
->Insert( _rMovedFwdFrameByObjPos
,
332 void SwLayouter::RemoveMovedFwdFrame( const SwDoc
& _rDoc
,
333 const SwTextFrame
& _rTextFrame
)
336 if ( SwLayouter::FrameMovedFwdByObjPos( _rDoc
, _rTextFrame
, nDummy
) )
338 _rDoc
.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames
->Remove( _rTextFrame
);
342 bool SwLayouter::FrameMovedFwdByObjPos( const SwDoc
& _rDoc
,
343 const SwTextFrame
& _rTextFrame
,
344 sal_uInt32
& _ornToPageNum
)
346 if ( !_rDoc
.getIDocumentLayoutAccess().GetLayouter() )
351 else if ( !_rDoc
.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames
)
358 return _rDoc
.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames
->
359 FrameMovedFwdByObjPos( _rTextFrame
, _ornToPageNum
);
364 bool SwLayouter::DoesRowContainMovedFwdFrame( const SwDoc
& _rDoc
,
365 const SwRowFrame
& _rRowFrame
)
367 if ( !_rDoc
.getIDocumentLayoutAccess().GetLayouter() )
371 else if ( !_rDoc
.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames
)
377 return _rDoc
.getIDocumentLayoutAccess().GetLayouter()->
378 mpMovedFwdFrames
->DoesRowContainMovedFwdFrame( _rRowFrame
);
383 void SwLayouter::ClearObjsTmpConsiderWrapInfluence( const SwDoc
& _rDoc
)
385 if ( _rDoc
.getIDocumentLayoutAccess().GetLayouter() &&
386 _rDoc
.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl
)
388 _rDoc
.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl
->Clear();
392 void SwLayouter::InsertObjForTmpConsiderWrapInfluence(
394 SwAnchoredObject
& _rAnchoredObj
)
396 if ( !_rDoc
.getIDocumentLayoutAccess().GetLayouter() )
398 const_cast<SwDoc
&>(_rDoc
).getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
401 if ( !_rDoc
.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl
)
403 const_cast<SwDoc
&>(_rDoc
).getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl
.reset(
404 new SwObjsMarkedAsTmpConsiderWrapInfluence());
407 _rDoc
.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl
->Insert( _rAnchoredObj
);
410 void SwLayouter::RemoveObjForTmpConsiderWrapInfluence(
412 SwAnchoredObject
& _rAnchoredObj
)
414 if ( !_rDoc
.getIDocumentLayoutAccess().GetLayouter() )
417 if ( !_rDoc
.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl
)
420 _rDoc
.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl
->Remove( _rAnchoredObj
);
424 void LOOPING_LOUIE_LIGHT( bool bCondition
, const SwTextFrame
& rTextFrame
)
428 const SwDoc
& rDoc
= *rTextFrame
.GetAttrSet()->GetDoc();
429 if ( rDoc
.getIDocumentLayoutAccess().GetLayouter() )
431 const_cast<SwDoc
&>(rDoc
).getIDocumentLayoutAccess().GetLayouter()->LoopingLouieLight( rDoc
, rTextFrame
);
437 bool SwLayouter::MoveBwdSuppressed( const SwDoc
& p_rDoc
,
438 const SwFlowFrame
& p_rFlowFrame
,
439 const SwLayoutFrame
& p_rNewUpperFrame
)
441 bool bMoveBwdSuppressed( false );
443 if ( !p_rDoc
.getIDocumentLayoutAccess().GetLayouter() )
445 const_cast<SwDoc
&>(p_rDoc
).getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
448 // create hash map key
449 tMoveBwdLayoutInfoKey aMoveBwdLayoutInfo
;
450 aMoveBwdLayoutInfo
.mnFrameId
= p_rFlowFrame
.GetFrame().GetFrameId();
451 aMoveBwdLayoutInfo
.mnNewUpperPosX
= p_rNewUpperFrame
.getFrameArea().Pos().X();
452 aMoveBwdLayoutInfo
.mnNewUpperPosY
= p_rNewUpperFrame
.getFrameArea().Pos().Y();
453 aMoveBwdLayoutInfo
.mnNewUpperWidth
= p_rNewUpperFrame
.getFrameArea().Width();
454 aMoveBwdLayoutInfo
.mnNewUpperHeight
= p_rNewUpperFrame
.getFrameArea().Height();
455 SwRectFnSet
aRectFnSet(&p_rNewUpperFrame
);
456 const SwFrame
* pLastLower( p_rNewUpperFrame
.Lower() );
457 while ( pLastLower
&& pLastLower
->GetNext() )
459 pLastLower
= pLastLower
->GetNext();
461 aMoveBwdLayoutInfo
.mnFreeSpaceInNewUpper
=
463 ? aRectFnSet
.BottomDist( pLastLower
->getFrameArea(), aRectFnSet
.GetPrtBottom(p_rNewUpperFrame
) )
464 : aRectFnSet
.GetHeight(p_rNewUpperFrame
.getFrameArea());
466 // check for moving backward suppress threshold
467 const sal_uInt16 cMoveBwdCountSuppressThreshold
= 20;
468 if ( ++const_cast<SwDoc
&>(p_rDoc
).getIDocumentLayoutAccess().GetLayouter()->maMoveBwdLayoutInfo
[ aMoveBwdLayoutInfo
] >
469 cMoveBwdCountSuppressThreshold
)
471 bMoveBwdSuppressed
= true;
474 return bMoveBwdSuppressed
;
477 void SwLayouter::ClearMoveBwdLayoutInfo( const SwDoc
& _rDoc
)
479 if ( _rDoc
.getIDocumentLayoutAccess().GetLayouter() )
480 const_cast<SwDoc
&>(_rDoc
).getIDocumentLayoutAccess().GetLayouter()->maMoveBwdLayoutInfo
.clear();
483 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */