xref: /trunk/main/sw/source/core/layout/layouter.cxx (revision efeef26f)
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