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