xref: /AOO41X/main/sw/source/core/layout/layouter.cxx (revision efeef26f81c84063fb0a91bde3856d4a51172d90)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 
29 #include "layouter.hxx"
30 #include "doc.hxx"
31 #include "sectfrm.hxx"
32 #include "ftnboss.hxx"
33 #include "cntfrm.hxx"
34 #include "pagefrm.hxx"
35 #include "ftnfrm.hxx"
36 #include "txtfrm.hxx"
37 
38 // --> OD 2004-06-23 #i28701#
39 #include <movedfwdfrmsbyobjpos.hxx>
40 // <--
41 // --> OD 2004-10-22 #i35911#
42 #include <objstmpconsiderwrapinfl.hxx>
43 // <--
44 
45 #define LOOP_DETECT 250
46 
47 class SwLooping
48 {
49     sal_uInt16 nMinPage;
50     sal_uInt16 nMaxPage;
51     sal_uInt16 nCount;
52     sal_uInt16 mnLoopControlStage;
53 public:
54     SwLooping( SwPageFrm* pPage );
55     void Control( SwPageFrm* pPage );
56     void Drastic( SwFrm* pFrm );
IsLoopingLouieLight() const57     bool IsLoopingLouieLight() const { return nCount > LOOP_DETECT - 30; };
58 };
59 
60 class SwEndnoter
61 {
62     SwLayouter* pMaster;
63     SwSectionFrm* pSect;
64     SvPtrarr* pEndArr;
65 public:
SwEndnoter(SwLayouter * pLay)66     SwEndnoter( SwLayouter* pLay )
67         : pMaster( pLay ), pSect( NULL ), pEndArr( NULL ) {}
~SwEndnoter()68     ~SwEndnoter() { delete pEndArr; }
69     void CollectEndnotes( SwSectionFrm* pSct );
70     void CollectEndnote( SwFtnFrm* pFtn );
GetSect()71     const SwSectionFrm* GetSect() { return pSect; }
72     void InsertEndnotes();
HasEndnotes() const73     sal_Bool HasEndnotes() const { return pEndArr && pEndArr->Count(); }
74 };
75 
CollectEndnotes(SwSectionFrm * pSct)76 void SwEndnoter::CollectEndnotes( SwSectionFrm* pSct )
77 {
78     ASSERT( pSct, "CollectEndnotes: Which section?" );
79     if( !pSect )
80         pSect = pSct;
81     else if( pSct != pSect )
82         return;
83     pSect->CollectEndnotes( pMaster );
84 }
85 
CollectEndnote(SwFtnFrm * pFtn)86 void SwEndnoter::CollectEndnote( SwFtnFrm* pFtn )
87 {
88     if( pEndArr && USHRT_MAX != pEndArr->GetPos( (VoidPtr)pFtn ) )
89         return;
90 
91     if( pFtn->GetUpper() )
92     {
93         // pFtn is the master, he incorporates its follows
94         SwFtnFrm *pNxt = pFtn->GetFollow();
95         while ( pNxt )
96         {
97             SwFrm *pCnt = pNxt->ContainsAny();
98             if ( pCnt )
99             {
100                 do
101                 {   SwFrm *pNxtCnt = pCnt->GetNext();
102                     pCnt->Cut();
103                     pCnt->Paste( pFtn );
104                     pCnt = pNxtCnt;
105                 } while ( pCnt );
106             }
107             else
108             {   ASSERT( pNxt->Lower() && pNxt->Lower()->IsSctFrm(),
109                         "Endnote without content?" );
110                 pNxt->Cut();
111                 delete pNxt;
112             }
113             pNxt = pFtn->GetFollow();
114         }
115         if( pFtn->GetMaster() )
116             return;
117         pFtn->Cut();
118     }
119     else if( pEndArr )
120     {
121         for ( sal_uInt16 i = 0; i < pEndArr->Count(); ++i )
122         {
123             SwFtnFrm *pEndFtn = (SwFtnFrm*)((*pEndArr)[i]);
124             if( pEndFtn->GetAttr() == pFtn->GetAttr() )
125             {
126                 delete pFtn;
127                 return;
128             }
129         }
130     }
131     if( !pEndArr )
132         pEndArr = new SvPtrarr( 5, 5 );  // deleted from the SwLayouter
133     pEndArr->Insert( (VoidPtr)pFtn, pEndArr->Count() );
134 }
135 
InsertEndnotes()136 void SwEndnoter::InsertEndnotes()
137 {
138     if( !pSect )
139         return;
140     if( !pEndArr || !pEndArr->Count() )
141     {
142         pSect = NULL;
143         return;
144     }
145     ASSERT( pSect->Lower() && pSect->Lower()->IsFtnBossFrm(),
146             "InsertEndnotes: Where's my column?" );
147     SwFrm* pRef = pSect->FindLastCntnt( FINDMODE_MYLAST );
148     SwFtnBossFrm *pBoss = pRef ? pRef->FindFtnBossFrm()
149                                : (SwFtnBossFrm*)pSect->Lower();
150     pBoss->_MoveFtns( *pEndArr );
151     delete pEndArr;
152     pEndArr = NULL;
153     pSect = NULL;
154 }
155 
SwLooping(SwPageFrm * pPage)156 SwLooping::SwLooping( SwPageFrm* pPage )
157 {
158     ASSERT( pPage, "Where's my page?" );
159     nMinPage = pPage->GetPhyPageNum();
160     nMaxPage = nMinPage;
161     nCount = 0;
162     mnLoopControlStage = 0;
163 }
164 
Drastic(SwFrm * pFrm)165 void SwLooping::Drastic( SwFrm* pFrm )
166 {
167     while( pFrm )
168     {
169         pFrm->ValidateThisAndAllLowers( mnLoopControlStage );
170         pFrm = pFrm->GetNext();
171     }
172 }
173 
Control(SwPageFrm * pPage)174 void SwLooping::Control( SwPageFrm* pPage )
175 {
176     if( !pPage )
177         return;
178     sal_uInt16 nNew = pPage->GetPhyPageNum();
179     if( nNew > nMaxPage )
180         nMaxPage = nNew;
181     if( nNew < nMinPage )
182     {
183         nMinPage = nNew;
184         nMaxPage = nNew;
185         nCount = 0;
186         mnLoopControlStage = 0;
187     }
188     else if( nNew > nMinPage + 2 )
189     {
190         nMinPage = nNew - 2;
191         nMaxPage = nNew;
192         nCount = 0;
193         mnLoopControlStage = 0;
194     }
195     else if( ++nCount > LOOP_DETECT )
196     {
197 #ifdef DBG_UTIL
198 #if OSL_DEBUG_LEVEL > 1
199         static sal_Bool bNoLouie = sal_False;
200         if( bNoLouie )
201             return;
202 #endif
203 #endif
204 
205         // FME 2007-08-30 #i81146# new loop control
206 #if OSL_DEBUG_LEVEL > 1
207         ASSERT( 0 != mnLoopControlStage, "Looping Louie: Stage 1!" );
208         ASSERT( 1 != mnLoopControlStage, "Looping Louie: Stage 2!!" );
209         ASSERT( 2 >  mnLoopControlStage, "Looping Louie: Stage 3!!!" );
210 #endif
211 
212         Drastic( pPage->Lower() );
213         if( nNew > nMinPage && pPage->GetPrev() )
214             Drastic( ((SwPageFrm*)pPage->GetPrev())->Lower() );
215         if( nNew < nMaxPage && pPage->GetNext() )
216             Drastic( ((SwPageFrm*)pPage->GetNext())->Lower() );
217 
218         ++mnLoopControlStage;
219         nCount = 0;
220     }
221 }
222 
223 /*************************************************************************
224 |*
225 |*  SwLayouter::SwLayouter()
226 |*
227 |*  Ersterstellung      AMA 02. Nov. 99
228 |*  Letzte Aenderung    AMA 02. Nov. 99
229 |*
230 |*************************************************************************/
231 
SwLayouter()232 SwLayouter::SwLayouter()
233         : pEndnoter( NULL ),
234           pLooping( NULL ),
235           // --> OD 2004-06-23 #i28701#
236           mpMovedFwdFrms( 0L ),
237           // <--
238           // --> OD 2004-10-22 #i35911#
239           mpObjsTmpConsiderWrapInfl( 0L )
240           // <--
241 {
242 }
243 
~SwLayouter()244 SwLayouter::~SwLayouter()
245 {
246     delete pEndnoter;
247     delete pLooping;
248     // --> OD 2004-06-23 #i28701#
249     delete mpMovedFwdFrms;
250     mpMovedFwdFrms = 0L;
251     // <--
252     // --> OD 2004-10-22 #i35911#
253     delete mpObjsTmpConsiderWrapInfl;
254     mpObjsTmpConsiderWrapInfl = 0L;
255     // <--
256 }
257 
_CollectEndnotes(SwSectionFrm * pSect)258 void SwLayouter::_CollectEndnotes( SwSectionFrm* pSect )
259 {
260     if( !pEndnoter )
261         pEndnoter = new SwEndnoter( this );
262     pEndnoter->CollectEndnotes( pSect );
263 }
264 
HasEndnotes() const265 sal_Bool SwLayouter::HasEndnotes() const
266 {
267     return pEndnoter->HasEndnotes();
268 }
269 
CollectEndnote(SwFtnFrm * pFtn)270 void SwLayouter::CollectEndnote( SwFtnFrm* pFtn )
271 {
272     pEndnoter->CollectEndnote( pFtn );
273 }
274 
InsertEndnotes(SwSectionFrm * pSect)275 void SwLayouter::InsertEndnotes( SwSectionFrm* pSect )
276 {
277     if( !pEndnoter || pEndnoter->GetSect() != pSect )
278         return;
279     pEndnoter->InsertEndnotes();
280 }
281 
LoopControl(SwPageFrm * pPage,sal_uInt8)282 void SwLayouter::LoopControl( SwPageFrm* pPage, sal_uInt8 )
283 {
284     ASSERT( pLooping, "Looping: Lost control" );
285     pLooping->Control( pPage );
286 }
287 
LoopingLouieLight(const SwDoc & rDoc,const SwTxtFrm & rFrm)288 void SwLayouter::LoopingLouieLight( const SwDoc& rDoc, const SwTxtFrm& rFrm )
289 {
290     if ( pLooping && pLooping->IsLoopingLouieLight() )
291     {
292 #if OSL_DEBUG_LEVEL > 1
293         ASSERT( false, "Looping Louie (Light): Fixating fractious frame" )
294 #endif
295         SwLayouter::InsertMovedFwdFrm( rDoc, rFrm, rFrm.FindPageFrm()->GetPhyPageNum() );
296     }
297 }
298 
StartLooping(SwPageFrm * pPage)299 sal_Bool SwLayouter::StartLooping( SwPageFrm* pPage )
300 {
301     if( pLooping )
302         return sal_False;
303     pLooping = new SwLooping( pPage );
304     return sal_True;
305 }
306 
EndLoopControl()307 void SwLayouter::EndLoopControl()
308 {
309     delete pLooping;
310     pLooping = NULL;
311 }
312 
CollectEndnotes(SwDoc * pDoc,SwSectionFrm * pSect)313 void SwLayouter::CollectEndnotes( SwDoc* pDoc, SwSectionFrm* pSect )
314 {
315     ASSERT( pDoc, "No doc, no fun" );
316     if( !pDoc->GetLayouter() )
317         pDoc->SetLayouter( new SwLayouter() );
318     pDoc->GetLayouter()->_CollectEndnotes( pSect );
319 }
320 
Collecting(SwDoc * pDoc,SwSectionFrm * pSect,SwFtnFrm * pFtn)321 sal_Bool SwLayouter::Collecting( SwDoc* pDoc, SwSectionFrm* pSect, SwFtnFrm* pFtn )
322 {
323     if( !pDoc->GetLayouter() )
324         return sal_False;
325     SwLayouter *pLayouter = pDoc->GetLayouter();
326     if( pLayouter->pEndnoter && pLayouter->pEndnoter->GetSect() && pSect &&
327         ( pLayouter->pEndnoter->GetSect()->IsAnFollow( pSect ) ||
328           pSect->IsAnFollow( pLayouter->pEndnoter->GetSect() ) ) )
329     {
330         if( pFtn )
331             pLayouter->CollectEndnote( pFtn );
332         return sal_True;
333     }
334     return sal_False;
335 }
336 
StartLoopControl(SwDoc * pDoc,SwPageFrm * pPage)337 sal_Bool SwLayouter::StartLoopControl( SwDoc* pDoc, SwPageFrm *pPage )
338 {
339     ASSERT( pDoc, "No doc, no fun" );
340     if( !pDoc->GetLayouter() )
341         pDoc->SetLayouter( new SwLayouter() );
342     return !pDoc->GetLayouter()->pLooping &&
343             pDoc->GetLayouter()->StartLooping( pPage );
344 }
345 
346 // --> OD 2004-06-23 #i28701#
347 // -----------------------------------------------------------------------------
348 // methods to manage text frames, which are moved forward by the positioning
349 // of its anchored objects
350 // -----------------------------------------------------------------------------
ClearMovedFwdFrms(const SwDoc & _rDoc)351 void SwLayouter::ClearMovedFwdFrms( const SwDoc& _rDoc )
352 {
353     if ( _rDoc.GetLayouter() &&
354          _rDoc.GetLayouter()->mpMovedFwdFrms )
355     {
356         _rDoc.GetLayouter()->mpMovedFwdFrms->Clear();
357     }
358 }
359 
InsertMovedFwdFrm(const SwDoc & _rDoc,const SwTxtFrm & _rMovedFwdFrmByObjPos,const sal_uInt32 _nToPageNum)360 void SwLayouter::InsertMovedFwdFrm( const SwDoc& _rDoc,
361                                     const SwTxtFrm& _rMovedFwdFrmByObjPos,
362                                     const sal_uInt32 _nToPageNum )
363 {
364     if ( !_rDoc.GetLayouter() )
365     {
366         const_cast<SwDoc&>(_rDoc).SetLayouter( new SwLayouter() );
367     }
368 
369     if ( !_rDoc.GetLayouter()->mpMovedFwdFrms )
370     {
371         const_cast<SwDoc&>(_rDoc).GetLayouter()->mpMovedFwdFrms =
372                                                 new SwMovedFwdFrmsByObjPos();
373     }
374 
375     _rDoc.GetLayouter()->mpMovedFwdFrms->Insert( _rMovedFwdFrmByObjPos,
376                                                  _nToPageNum );
377 }
378 
379 // --> OD 2005-01-12 #i40155#
RemoveMovedFwdFrm(const SwDoc & _rDoc,const SwTxtFrm & _rTxtFrm)380 void SwLayouter::RemoveMovedFwdFrm( const SwDoc& _rDoc,
381                                     const SwTxtFrm& _rTxtFrm )
382 {
383     sal_uInt32 nDummy;
384     if ( SwLayouter::FrmMovedFwdByObjPos( _rDoc, _rTxtFrm, nDummy ) )
385     {
386         _rDoc.GetLayouter()->mpMovedFwdFrms->Remove( _rTxtFrm );
387     }
388 }
389 // <--
390 
FrmMovedFwdByObjPos(const SwDoc & _rDoc,const SwTxtFrm & _rTxtFrm,sal_uInt32 & _ornToPageNum)391 bool SwLayouter::FrmMovedFwdByObjPos( const SwDoc& _rDoc,
392                                       const SwTxtFrm& _rTxtFrm,
393                                       sal_uInt32& _ornToPageNum )
394 {
395     if ( !_rDoc.GetLayouter() )
396     {
397         _ornToPageNum = 0;
398         return false;
399     }
400     else if ( !_rDoc.GetLayouter()->mpMovedFwdFrms )
401     {
402         _ornToPageNum = 0;
403         return false;
404     }
405     else
406     {
407         return _rDoc.GetLayouter()->mpMovedFwdFrms->
408                                 FrmMovedFwdByObjPos( _rTxtFrm, _ornToPageNum );
409     }
410 }
411 // <--
412 // --> OD 2004-10-05 #i26945#
DoesRowContainMovedFwdFrm(const SwDoc & _rDoc,const SwRowFrm & _rRowFrm)413 bool SwLayouter::DoesRowContainMovedFwdFrm( const SwDoc& _rDoc,
414                                             const SwRowFrm& _rRowFrm )
415 {
416     if ( !_rDoc.GetLayouter() )
417     {
418         return false;
419     }
420     else if ( !_rDoc.GetLayouter()->mpMovedFwdFrms )
421     {
422         return false;
423     }
424     else
425     {
426         return _rDoc.GetLayouter()->
427                         mpMovedFwdFrms->DoesRowContainMovedFwdFrm( _rRowFrm );
428     }
429 }
430 // <--
431 
432 // --> OD 2004-10-22 #i35911#
ClearObjsTmpConsiderWrapInfluence(const SwDoc & _rDoc)433 void SwLayouter::ClearObjsTmpConsiderWrapInfluence( const SwDoc& _rDoc )
434 {
435     if ( _rDoc.GetLayouter() &&
436          _rDoc.GetLayouter()->mpObjsTmpConsiderWrapInfl )
437     {
438         _rDoc.GetLayouter()->mpObjsTmpConsiderWrapInfl->Clear();
439     }
440 }
InsertObjForTmpConsiderWrapInfluence(const SwDoc & _rDoc,SwAnchoredObject & _rAnchoredObj)441 void SwLayouter::InsertObjForTmpConsiderWrapInfluence(
442                                             const SwDoc& _rDoc,
443                                             SwAnchoredObject& _rAnchoredObj )
444 {
445     if ( !_rDoc.GetLayouter() )
446     {
447         const_cast<SwDoc&>(_rDoc).SetLayouter( new SwLayouter() );
448     }
449 
450     if ( !_rDoc.GetLayouter()->mpObjsTmpConsiderWrapInfl )
451     {
452         const_cast<SwDoc&>(_rDoc).GetLayouter()->mpObjsTmpConsiderWrapInfl =
453                                 new SwObjsMarkedAsTmpConsiderWrapInfluence();
454     }
455 
456     _rDoc.GetLayouter()->mpObjsTmpConsiderWrapInfl->Insert( _rAnchoredObj );
457 }
458 // <--
459 // --> OD 2005-01-12 #i40155#
ClearFrmsNotToWrap(const SwDoc & _rDoc)460 void SwLayouter::ClearFrmsNotToWrap( const SwDoc& _rDoc )
461 {
462     if ( _rDoc.GetLayouter() )
463     {
464         const_cast<SwDoc&>(_rDoc).GetLayouter()->maFrmsNotToWrap.clear();
465     }
466 }
467 
InsertFrmNotToWrap(const SwDoc & _rDoc,const SwFrm & _rFrm)468 void SwLayouter::InsertFrmNotToWrap( const SwDoc& _rDoc,
469                                              const SwFrm& _rFrm )
470 {
471     if ( !_rDoc.GetLayouter() )
472     {
473         const_cast<SwDoc&>(_rDoc).SetLayouter( new SwLayouter() );
474     }
475 
476     if ( !SwLayouter::FrmNotToWrap( _rDoc, _rFrm ) )
477     {
478         const_cast<SwDoc&>(_rDoc).GetLayouter()->maFrmsNotToWrap.push_back( &_rFrm );
479     }
480 }
481 
FrmNotToWrap(const IDocumentLayoutAccess & _rDLA,const SwFrm & _rFrm)482 bool SwLayouter::FrmNotToWrap( const IDocumentLayoutAccess& _rDLA,
483                                const SwFrm& _rFrm )
484 {
485     const SwLayouter* pLayouter = _rDLA.GetLayouter();
486     if ( !pLayouter )
487     {
488         return false;
489     }
490     else
491     {
492         bool bFrmNotToWrap( false );
493         std::vector< const SwFrm* >::const_iterator aIter =
494                             pLayouter->maFrmsNotToWrap.begin();
495         for ( ; aIter != pLayouter->maFrmsNotToWrap.end(); ++aIter )
496         {
497             const SwFrm* pFrm = *(aIter);
498             if ( pFrm == &_rFrm )
499             {
500                 bFrmNotToWrap = true;
501                 break;
502             }
503         }
504         return bFrmNotToWrap;
505     }
506 }
507 // <--
508 
LOOPING_LOUIE_LIGHT(bool bCondition,const SwTxtFrm & rTxtFrm)509 void LOOPING_LOUIE_LIGHT( bool bCondition, const SwTxtFrm& rTxtFrm )
510 {
511     if ( bCondition )
512     {
513         const SwDoc& rDoc = *rTxtFrm.GetAttrSet()->GetDoc();
514         if ( rDoc.GetLayouter() )
515         {
516             const_cast<SwDoc&>(rDoc).GetLayouter()->LoopingLouieLight( rDoc, rTxtFrm );
517         }
518     }
519 }
520 
521 // --> OD 2006-05-10 #i65250#
MoveBwdSuppressed(const SwDoc & p_rDoc,const SwFlowFrm & p_rFlowFrm,const SwLayoutFrm & p_rNewUpperFrm)522 bool SwLayouter::MoveBwdSuppressed( const SwDoc& p_rDoc,
523                                     const SwFlowFrm& p_rFlowFrm,
524                                     const SwLayoutFrm& p_rNewUpperFrm )
525 {
526     bool bMoveBwdSuppressed( false );
527 
528     if ( !p_rDoc.GetLayouter() )
529     {
530         const_cast<SwDoc&>(p_rDoc).SetLayouter( new SwLayouter() );
531     }
532 
533     // create hash map key
534     tMoveBwdLayoutInfoKey aMoveBwdLayoutInfo;
535     aMoveBwdLayoutInfo.mnFrmId = p_rFlowFrm.GetFrm()->GetFrmId();
536     aMoveBwdLayoutInfo.mnNewUpperPosX = p_rNewUpperFrm.Frm().Pos().X();
537     aMoveBwdLayoutInfo.mnNewUpperPosY = p_rNewUpperFrm.Frm().Pos().Y();
538     aMoveBwdLayoutInfo.mnNewUpperWidth = p_rNewUpperFrm.Frm().Width();
539     aMoveBwdLayoutInfo.mnNewUpperHeight =  p_rNewUpperFrm.Frm().Height();
540     SWRECTFN( (&p_rNewUpperFrm) )
541     const SwFrm* pLastLower( p_rNewUpperFrm.Lower() );
542     while ( pLastLower && pLastLower->GetNext() )
543     {
544         pLastLower = pLastLower->GetNext();
545     }
546     aMoveBwdLayoutInfo.mnFreeSpaceInNewUpper =
547             pLastLower
548             ? (pLastLower->Frm().*fnRect->fnBottomDist)( (p_rNewUpperFrm.*fnRect->fnGetPrtBottom)() )
549             : (p_rNewUpperFrm.Frm().*fnRect->fnGetHeight)();
550 
551     // check for moving backward suppress threshold
552     const sal_uInt16 cMoveBwdCountSuppressThreshold = 20;
553     if ( ++const_cast<SwDoc&>(p_rDoc).GetLayouter()->maMoveBwdLayoutInfo[ aMoveBwdLayoutInfo ] >
554                                                 cMoveBwdCountSuppressThreshold )
555     {
556         bMoveBwdSuppressed = true;
557     }
558 
559     return bMoveBwdSuppressed;
560 }
561 
ClearMoveBwdLayoutInfo(const SwDoc & _rDoc)562 void SwLayouter::ClearMoveBwdLayoutInfo( const SwDoc& _rDoc )
563 {
564     if ( _rDoc.GetLayouter() )
565         const_cast<SwDoc&>(_rDoc).GetLayouter()->maMoveBwdLayoutInfo.clear();
566 }
567 // <--
568