LibreOffice Module sw (master)  1
layouter.cxx
Go to the documentation of this file.
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 <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>
28 
29 #include <movedfwdfrmsbyobjpos.hxx>
31 
32 #define LOOP_DETECT 250
33 
34 class SwLooping
35 {
36  sal_uInt16 nMinPage;
37  sal_uInt16 nMaxPage;
38  sal_uInt16 nCount;
39  sal_uInt16 mnLoopControlStage;
40 public:
41  explicit SwLooping( SwPageFrame const * pPage );
42  void Control( SwPageFrame* pPage );
43  void Drastic( SwFrame* pFrame );
44  bool IsLoopingLouieLight() const { return nCount > LOOP_DETECT - 30; };
45 };
46 
48 {
51  std::unique_ptr<SwFootnoteFrames> pEndArr;
52 public:
53  explicit SwEndnoter( SwLayouter* pLay )
54  : pMaster( pLay ), pSect( nullptr ) {}
55  void CollectEndnotes( SwSectionFrame* pSct );
56  void CollectEndnote( SwFootnoteFrame* pFootnote );
57  const SwSectionFrame* GetSect() const { return pSect; }
58  void InsertEndnotes();
59  bool HasEndnotes() const { return pEndArr && !pEndArr->empty(); }
60 };
61 
63 {
64  OSL_ENSURE( pSct, "CollectEndnotes: Which section?" );
65  if( !pSect )
66  pSect = pSct;
67  else if( pSct != pSect )
68  return;
70 }
71 
73 {
74  if( pEndArr && pEndArr->end() != std::find( pEndArr->begin(), pEndArr->end(), pFootnote ) )
75  return;
76 
77  if( pFootnote->GetUpper() )
78  {
79  // pFootnote is the master, he incorporates its follows
80  SwFootnoteFrame *pNxt = pFootnote->GetFollow();
81  while ( pNxt )
82  {
83  SwFrame *pCnt = pNxt->ContainsAny();
84  if ( pCnt )
85  {
86  do
87  { SwFrame *pNxtCnt = pCnt->GetNext();
88  pCnt->Cut();
89  pCnt->Paste( pFootnote );
90  pCnt = pNxtCnt;
91  } while ( pCnt );
92  }
93  else
94  {
95  OSL_ENSURE( pNxt->Lower() && pNxt->Lower()->IsSctFrame(),
96  "Endnote without content?" );
97  pNxt->Cut();
99  }
100  pNxt = pFootnote->GetFollow();
101  }
102  if( pFootnote->GetMaster() )
103  return;
104  pFootnote->Cut();
105  }
106  else if( pEndArr )
107  {
108  for (SwFootnoteFrame* pEndFootnote : *pEndArr)
109  {
110  if( pEndFootnote->GetAttr() == pFootnote->GetAttr() )
111  {
112  SwFrame::DestroyFrame(pFootnote);
113  return;
114  }
115  }
116  }
117  if( !pEndArr )
118  pEndArr.reset( new SwFootnoteFrames ); // deleted from the SwLayouter
119  pEndArr->push_back( pFootnote );
120 }
121 
123 {
124  if( !pSect )
125  return;
126  if( !pEndArr || pEndArr->empty() )
127  {
128  pSect = nullptr;
129  return;
130  }
131  OSL_ENSURE( pSect->Lower() && pSect->Lower()->IsFootnoteBossFrame(),
132  "InsertEndnotes: Where's my column?" );
134  SwFootnoteBossFrame *pBoss = pRef ? pRef->FindFootnoteBossFrame()
135  : static_cast<SwFootnoteBossFrame*>(pSect->Lower());
136  pBoss->MoveFootnotes_( *pEndArr );
137  pEndArr.reset();
138  pSect = nullptr;
139 }
140 
142 {
143  OSL_ENSURE( pPage, "Where's my page?" );
144  nMinPage = pPage->GetPhyPageNum();
145  nMaxPage = nMinPage;
146  nCount = 0;
147  mnLoopControlStage = 0;
148 }
149 
151 {
152  while( pFrame )
153  {
155  pFrame = pFrame->GetNext();
156  }
157 }
158 
160 {
161  if( !pPage )
162  return;
163  const sal_uInt16 nNew = pPage->GetPhyPageNum();
164  if( nNew > nMaxPage )
165  nMaxPage = nNew;
166  if( nNew < nMinPage )
167  {
168  nMinPage = nNew;
169  nMaxPage = nNew;
170  nCount = 0;
171  mnLoopControlStage = 0;
172  }
173  else if( nNew > nMinPage + 2 )
174  {
175  nMinPage = nNew - 2;
176  nMaxPage = nNew;
177  nCount = 0;
178  mnLoopControlStage = 0;
179  }
180  else if( ++nCount > LOOP_DETECT )
181  {
182 #if OSL_DEBUG_LEVEL > 1
183  static bool bNoLouie = false;
184  if( bNoLouie )
185  return;
186 
187  // FME 2007-08-30 #i81146# new loop control
188  OSL_ENSURE( 0 != mnLoopControlStage, "Looping Louie: Stage 1!" );
189  OSL_ENSURE( 1 != mnLoopControlStage, "Looping Louie: Stage 2!!" );
190  OSL_ENSURE( 2 > mnLoopControlStage, "Looping Louie: Stage 3!!!" );
191 #endif
192 
193  Drastic( pPage->Lower() );
194  if( nNew > nMinPage && pPage->GetPrev() )
195  Drastic( static_cast<SwPageFrame*>(pPage->GetPrev())->Lower() );
196  if( nNew < nMaxPage && pPage->GetNext() )
197  Drastic( static_cast<SwPageFrame*>(pPage->GetNext())->Lower() );
198 
200  nCount = 0;
201  }
202 }
203 
205 {
206 }
207 
209 {
210 }
211 
213 {
214  if( !mpEndnoter )
215  mpEndnoter.reset(new SwEndnoter( this ));
216  mpEndnoter->CollectEndnotes( pSect );
217 }
218 
220 {
221  return mpEndnoter->HasEndnotes();
222 }
223 
225 {
226  mpEndnoter->CollectEndnote( pFootnote );
227 }
228 
230 {
231  if( !mpEndnoter || mpEndnoter->GetSect() != pSect )
232  return;
233  mpEndnoter->InsertEndnotes();
234 }
235 
237 {
238  OSL_ENSURE( mpLooping, "Looping: Lost control" );
239  mpLooping->Control( pPage );
240 }
241 
242 void SwLayouter::LoopingLouieLight( const SwDoc& rDoc, const SwTextFrame& rFrame )
243 {
244  if ( mpLooping && mpLooping->IsLoopingLouieLight() )
245  {
246 #if OSL_DEBUG_LEVEL > 1
247  OSL_FAIL( "Looping Louie (Light): Fixating fractious frame" );
248 #endif
249  SwLayouter::InsertMovedFwdFrame( rDoc, rFrame, rFrame.FindPageFrame()->GetPhyPageNum() );
250  }
251 }
252 
254 {
255  if( mpLooping )
256  return false;
257  mpLooping.reset(new SwLooping( pPage ));
258  return true;
259 }
260 
262 {
263  mpLooping.reset();
264 }
265 
267 {
268  assert(pDoc && "No doc, no fun");
269  if( !pDoc->getIDocumentLayoutAccess().GetLayouter() )
272 }
273 
274 bool SwLayouter::Collecting( SwDoc* pDoc, SwSectionFrame const * pSect, SwFootnoteFrame* pFootnote )
275 {
276  if( !pDoc->getIDocumentLayoutAccess().GetLayouter() )
277  return false;
278  SwLayouter *pLayouter = pDoc->getIDocumentLayoutAccess().GetLayouter();
279  if( pLayouter->mpEndnoter && pLayouter->mpEndnoter->GetSect() && pSect &&
280  ( pLayouter->mpEndnoter->GetSect()->IsAnFollow( pSect ) ||
281  pSect->IsAnFollow( pLayouter->mpEndnoter->GetSect() ) ) )
282  {
283  if( pFootnote )
284  pLayouter->CollectEndnote( pFootnote );
285  return true;
286  }
287  return false;
288 }
289 
290 bool SwLayouter::StartLoopControl( SwDoc* pDoc, SwPageFrame const *pPage )
291 {
292  OSL_ENSURE( pDoc, "No doc, no fun" );
293  if( !pDoc->getIDocumentLayoutAccess().GetLayouter() )
295  return !pDoc->getIDocumentLayoutAccess().GetLayouter()->mpLooping &&
297 }
298 
299 // #i28701#
300 // methods to manage text frames, which are moved forward by the positioning
301 // of its anchored objects
303 {
304  if ( _rDoc.getIDocumentLayoutAccess().GetLayouter() &&
306  {
308  }
309 }
310 
312  const SwTextFrame& _rMovedFwdFrameByObjPos,
313  const sal_uInt32 _nToPageNum )
314 {
315  if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() )
316  {
317  const_cast<SwDoc&>(_rDoc).getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
318  }
319 
321  {
322  const_cast<SwDoc&>(_rDoc).getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames.reset(
324  }
325 
326  _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames->Insert( _rMovedFwdFrameByObjPos,
327  _nToPageNum );
328 }
329 
330 // #i40155#
332  const SwTextFrame& _rTextFrame )
333 {
334  sal_uInt32 nDummy;
335  if ( SwLayouter::FrameMovedFwdByObjPos( _rDoc, _rTextFrame, nDummy ) )
336  {
337  _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpMovedFwdFrames->Remove( _rTextFrame );
338  }
339 }
340 
342  const SwTextFrame& _rTextFrame,
343  sal_uInt32& _ornToPageNum )
344 {
345  if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() )
346  {
347  _ornToPageNum = 0;
348  return false;
349  }
351  {
352  _ornToPageNum = 0;
353  return false;
354  }
355  else
356  {
358  FrameMovedFwdByObjPos( _rTextFrame, _ornToPageNum );
359  }
360 }
361 
362 // #i26945#
364  const SwRowFrame& _rRowFrame )
365 {
366  if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() )
367  {
368  return false;
369  }
371  {
372  return false;
373  }
374  else
375  {
376  return _rDoc.getIDocumentLayoutAccess().GetLayouter()->
377  mpMovedFwdFrames->DoesRowContainMovedFwdFrame( _rRowFrame );
378  }
379 }
380 
381 // #i35911#
383 {
384  if ( _rDoc.getIDocumentLayoutAccess().GetLayouter() &&
386  {
388  }
389 }
390 
392  const SwDoc& _rDoc,
393  SwAnchoredObject& _rAnchoredObj )
394 {
395  if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() )
396  {
397  const_cast<SwDoc&>(_rDoc).getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
398  }
399 
401  {
402  const_cast<SwDoc&>(_rDoc).getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl.reset(
404  }
405 
406  _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl->Insert( _rAnchoredObj );
407 }
408 
410  const SwDoc& _rDoc,
411  SwAnchoredObject& _rAnchoredObj )
412 {
413  if ( !_rDoc.getIDocumentLayoutAccess().GetLayouter() )
414  return;
415 
417  return;
418 
419  _rDoc.getIDocumentLayoutAccess().GetLayouter()->mpObjsTmpConsiderWrapInfl->Remove( _rAnchoredObj );
420 }
421 
422 
423 void LOOPING_LOUIE_LIGHT( bool bCondition, const SwTextFrame& rTextFrame )
424 {
425  if ( bCondition )
426  {
427  const SwDoc& rDoc = *rTextFrame.GetAttrSet()->GetDoc();
428  if ( rDoc.getIDocumentLayoutAccess().GetLayouter() )
429  {
430  const_cast<SwDoc&>(rDoc).getIDocumentLayoutAccess().GetLayouter()->LoopingLouieLight( rDoc, rTextFrame );
431  }
432  }
433 }
434 
435 // #i65250#
437  const SwFlowFrame& p_rFlowFrame,
438  const SwLayoutFrame& p_rNewUpperFrame )
439 {
440  bool bMoveBwdSuppressed( false );
441 
442  if ( !p_rDoc.getIDocumentLayoutAccess().GetLayouter() )
443  {
444  const_cast<SwDoc&>(p_rDoc).getIDocumentLayoutAccess().SetLayouter( new SwLayouter() );
445  }
446 
447  // create hash map key
448  tMoveBwdLayoutInfoKey aMoveBwdLayoutInfo;
449  aMoveBwdLayoutInfo.mnFrameId = p_rFlowFrame.GetFrame().GetFrameId();
450  aMoveBwdLayoutInfo.mnNewUpperPosX = p_rNewUpperFrame.getFrameArea().Pos().X();
451  aMoveBwdLayoutInfo.mnNewUpperPosY = p_rNewUpperFrame.getFrameArea().Pos().Y();
452  aMoveBwdLayoutInfo.mnNewUpperWidth = p_rNewUpperFrame.getFrameArea().Width();
453  aMoveBwdLayoutInfo.mnNewUpperHeight = p_rNewUpperFrame.getFrameArea().Height();
454  SwRectFnSet aRectFnSet(&p_rNewUpperFrame);
455  const SwFrame* pLastLower( p_rNewUpperFrame.Lower() );
456  while ( pLastLower && pLastLower->GetNext() )
457  {
458  pLastLower = pLastLower->GetNext();
459  }
460  aMoveBwdLayoutInfo.mnFreeSpaceInNewUpper =
461  pLastLower
462  ? aRectFnSet.BottomDist( pLastLower->getFrameArea(), aRectFnSet.GetPrtBottom(p_rNewUpperFrame) )
463  : aRectFnSet.GetHeight(p_rNewUpperFrame.getFrameArea());
464 
465  // check for moving backward suppress threshold
466  const sal_uInt16 cMoveBwdCountSuppressThreshold = 20;
467  if ( ++const_cast<SwDoc&>(p_rDoc).getIDocumentLayoutAccess().GetLayouter()->maMoveBwdLayoutInfo[ aMoveBwdLayoutInfo ] >
468  cMoveBwdCountSuppressThreshold )
469  {
470  bMoveBwdSuppressed = true;
471  }
472 
473  return bMoveBwdSuppressed;
474 }
475 
477 {
478  if ( _rDoc.getIDocumentLayoutAccess().GetLayouter() )
479  const_cast<SwDoc&>(_rDoc).getIDocumentLayoutAccess().GetLayouter()->maMoveBwdLayoutInfo.clear();
480 }
481 
482 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
Base class of the Writer layout elements.
Definition: frame.hxx:295
Base class that provides the general functionalities for frames that are allowed at page breaks (flow...
Definition: flowfrm.hxx:58
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:149
void LOOPING_LOUIE_LIGHT(bool bCondition, const SwTextFrame &rTextFrame)
Definition: layouter.cxx:423
long BottomDist(const SwRect &rRect, long nPos) const
Definition: frame.hxx:1375
void CollectEndnotes(SwSectionFrame *pSct)
Definition: layouter.cxx:62
void LoopControl(SwPageFrame *pPage)
Definition: layouter.cxx:236
std::unique_ptr< SwObjsMarkedAsTmpConsiderWrapInfluence > mpObjsTmpConsiderWrapInfl
Definition: layouter.hxx:53
static void ClearObjsTmpConsiderWrapInfluence(const SwDoc &_rDoc)
Definition: layouter.cxx:382
Definition: doc.hxx:185
void Height(long nNew)
Definition: swrect.hxx:189
#define LOOP_DETECT
Definition: layouter.cxx:32
bool StartLooping(SwPageFrame const *pPage)
Definition: layouter.cxx:253
sal_uInt16 nMaxPage
Definition: layouter.cxx:37
static void DestroyFrame(SwFrame *const pFrame)
this is the only way to delete a SwFrame instance
Definition: ssfrm.cxx:382
static bool StartLoopControl(SwDoc *pDoc, SwPageFrame const *pPage)
Definition: layouter.cxx:290
void Pos(const Point &rNew)
Definition: swrect.hxx:167
std::unique_ptr< SwMovedFwdFramesByObjPos > mpMovedFwdFrames
Definition: layouter.hxx:51
virtual void Cut() override
Definition: ftnfrm.cxx:499
std::unique_ptr< SwFootnoteFrames > pEndArr
Definition: layouter.cxx:51
static void InsertObjForTmpConsiderWrapInfluence(const SwDoc &_rDoc, SwAnchoredObject &_rAnchoredObj)
Definition: layouter.cxx:391
sal_uInt16 GetPhyPageNum() const
Definition: pagefrm.hxx:189
static bool Collecting(SwDoc *pDoc, SwSectionFrame const *pSect, SwFootnoteFrame *pFootnote)
Definition: layouter.cxx:274
SwLooping(SwPageFrame const *pPage)
Definition: layouter.cxx:141
wrapper class for the positioning of Writer fly frames and drawing objects
long GetPrtBottom(const SwFrame &rFrame) const
Definition: frame.hxx:1371
void MoveFootnotes_(SwFootnoteFrames &rFootnoteArr, bool bCalc=false)
Definition: ftnfrm.cxx:1917
const SwRect & getFrameArea() const
Definition: frame.hxx:175
void CollectEndnote(SwFootnoteFrame *pFootnote)
Definition: layouter.cxx:224
void EndLoopControl()
Definition: layouter.cxx:261
static bool DoesRowContainMovedFwdFrame(const SwDoc &_rDoc, const SwRowFrame &_rRowFrame)
Definition: layouter.cxx:363
static void RemoveObjForTmpConsiderWrapInfluence(const SwDoc &_rDoc, SwAnchoredObject &_rAnchoredObj)
Definition: layouter.cxx:409
std::unique_ptr< SwEndnoter > mpEndnoter
Definition: layouter.hxx:45
bool IsSctFrame() const
Definition: frame.hxx:1190
bool HasEndnotes() const
Definition: layouter.cxx:59
const SwAttrSet * GetAttrSet() const
WARNING: this may not return correct RES_PAGEDESC/RES_BREAK items for SwTextFrame, use GetBreakItem()/GetPageDescItem() instead.
Definition: findfrm.cxx:674
static bool MoveBwdSuppressed(const SwDoc &p_rDoc, const SwFlowFrame &p_rFlowFrame, const SwLayoutFrame &p_rNewUpperFrame)
Definition: layouter.cxx:436
const SwFrame & GetFrame() const
Definition: flowfrm.hxx:151
virtual void Paste(SwFrame *pParent, SwFrame *pSibling=nullptr)=0
virtual void Cut()=0
virtual void SetLayouter(SwLayouter *pNew)=0
std::unique_ptr< SwLooping > mpLooping
Definition: layouter.hxx:46
SwPageFrame * FindPageFrame()
Definition: frame.hxx:658
static void RemoveMovedFwdFrame(const SwDoc &_rDoc, const SwTextFrame &_rTextFrame)
Definition: layouter.cxx:331
void CollectEndnote(SwFootnoteFrame *pFootnote)
Definition: layouter.cxx:72
const SwFrame * Lower() const
Definition: layfrm.hxx:100
void Drastic(SwFrame *pFrame)
Definition: layouter.cxx:150
virtual SwLayouter * GetLayouter()=0
SwLayouter *const pMaster
Definition: layouter.cxx:49
SwLayoutFrame * GetUpper()
Definition: frame.hxx:656
SwFootnoteBossFrame * FindFootnoteBossFrame(bool bFootnotes=false)
Definition: findfrm.cxx:435
SwFrame * GetPrev()
Definition: frame.hxx:655
sal_uInt16 nMinPage
Definition: layouter.cxx:36
SwContentFrame * FindLastContent(SwFindMode nMode=SwFindMode::None)
Definition: sectfrm.cxx:905
A page of the document layout.
Definition: pagefrm.hxx:40
IDocumentLayoutAccess const & getIDocumentLayoutAccess() const
Definition: doc.cxx:437
const SwFootnoteFrame * GetMaster() const
Definition: ftnfrm.hxx:104
void CollectEndnotes(SwLayouter *pLayouter)
Definition: sectfrm.cxx:1039
void InsertEndnotes(SwSectionFrame const *pSect)
Definition: layouter.cxx:229
sal_uInt16 mnLoopControlStage
Definition: layouter.cxx:39
SwEndnoter(SwLayouter *pLay)
Definition: layouter.cxx:53
void Width(long nNew)
Definition: swrect.hxx:185
const SwFrame * ContainsAny(const bool _bInvestigateFootnoteForSections=false) const
Method doesn't investigate content of footnotes by default.
Definition: findfrm.cxx:125
static void ClearMoveBwdLayoutInfo(const SwDoc &p_rDoc)
Definition: layouter.cxx:476
const SwSectionFrame * GetSect() const
Definition: layouter.cxx:57
const SwFootnoteFrame * GetFollow() const
Definition: ftnfrm.hxx:101
const SwDoc * GetDoc() const
Definition: swatrset.hxx:204
bool IsLoopingLouieLight() const
Definition: layouter.cxx:44
sal_uInt16 nCount
Definition: layouter.cxx:38
const SwTextFootnote * GetAttr() const
Definition: ftnfrm.hxx:107
long GetHeight(const SwRect &rRect) const
Definition: frame.hxx:1343
void InsertEndnotes()
Definition: layouter.cxx:122
bool IsAnFollow(const SwFlowFrame *pFlow) const
Definition: flowfrm.cxx:666
void ValidateThisAndAllLowers(const sal_uInt16 nStage)
Definition: wsfrm.cxx:2016
void LoopingLouieLight(const SwDoc &rDoc, const SwTextFrame &rFrame)
Definition: layouter.cxx:242
bool IsFootnoteBossFrame() const
Definition: frame.hxx:1162
SwSectionFrame * pSect
Definition: layouter.cxx:50
static bool FrameMovedFwdByObjPos(const SwDoc &_rDoc, const SwTextFrame &_rTextFrame, sal_uInt32 &_ornToPageNum)
Definition: layouter.cxx:341
std::vector< SwFootnoteFrame * > SwFootnoteFrames
Definition: ftnboss.hxx:46
bool HasEndnotes() const
Definition: layouter.cxx:219
static void CollectEndnotes(SwDoc *pDoc, SwSectionFrame *pSect)
Definition: layouter.cxx:266
sal_uInt32 GetFrameId() const
Definition: frame.hxx:170
void Control(SwPageFrame *pPage)
Definition: layouter.cxx:159
static void InsertMovedFwdFrame(const SwDoc &_rDoc, const SwTextFrame &_rMovedFwdFrameByObjPos, const sal_uInt32 _nToPageNum)
Definition: layouter.cxx:311
SwRowFrame is one table row in the document layout.
Definition: rowfrm.hxx:28
void CollectEndnotes_(SwSectionFrame *pSect)
Definition: layouter.cxx:212
static void ClearMovedFwdFrames(const SwDoc &_rDoc)
Definition: layouter.cxx:302
SwFrame * GetNext()
Definition: frame.hxx:654