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