xref: /trunk/main/sw/source/core/layout/calcmove.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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 #include "rootfrm.hxx"
31 #include "pagefrm.hxx"
32 #include "cntfrm.hxx"
33 #include "viewsh.hxx"
34 #include "doc.hxx"
35 #include "viewimp.hxx"
36 #include "viewopt.hxx"
37 #include "swtypes.hxx"
38 #include "dflyobj.hxx"
39 #include "dcontact.hxx"
40 #include "flyfrm.hxx"
41 #include "frmtool.hxx"
42 #include "txtftn.hxx"
43 #include "fmtftn.hxx"
44 #include <editeng/ulspitem.hxx>
45 #include <editeng/keepitem.hxx>
46 
47 #include <vcl/outdev.hxx>
48 #include <fmtfsize.hxx>
49 #include <fmtanchr.hxx>
50 #include <fmtclbl.hxx>
51 
52 #include "tabfrm.hxx"
53 #include "ftnfrm.hxx"
54 #include "txtfrm.hxx"
55 #include "pagedesc.hxx"
56 #include "ftninfo.hxx"
57 #include "sectfrm.hxx"
58 #include "dbg_lay.hxx"
59 
60 // --> OD 2004-06-23 #i28701#
61 #include <sortedobjs.hxx>
62 #include <layouter.hxx>
63 // --> OD 2004-11-01 #i36347#
64 #include <flyfrms.hxx>
65 // <--
66 
67 //------------------------------------------------------------------------
68 //              Move-Methoden
69 //------------------------------------------------------------------------
70 
71 /*************************************************************************
72 |*
73 |*  SwCntntFrm::ShouldBwdMoved()
74 |*
75 |*  Beschreibung        Returnwert sagt, ob der Frm verschoben werden sollte.
76 |*  Ersterstellung      MA 05. Dec. 96
77 |*  Letzte Aenderung    MA 05. Dec. 96
78 |*
79 |*************************************************************************/
80 
81 
82 sal_Bool SwCntntFrm::ShouldBwdMoved( SwLayoutFrm *pNewUpper, sal_Bool, sal_Bool & )
83 {
84     if ( (SwFlowFrm::IsMoveBwdJump() || !IsPrevObjMove()))
85     {
86         //Das zurueckfliessen von Frm's ist leider etwas Zeitintensiv.
87         //Der haufigste Fall ist der, dass dort wo der Frm hinfliessen
88         //moechte die FixSize die gleiche ist, die der Frm selbst hat.
89         //In diesem Fall kann einfach geprueft werden, ob der Frm genug
90         //Platz fuer seine VarSize findet, ist dies nicht der Fall kann
91         //gleich auf das Verschieben verzichtet werden.
92         //Die Pruefung, ob der Frm genug Platz findet fuehrt er selbst
93         //durch, dabei wird beruecksichtigt, dass er sich moeglicherweise
94         //aufspalten kann.
95         //Wenn jedoch die FixSize eine andere ist oder Flys im Spiel sind
96         //(an der alten oder neuen Position) hat alle Prueferei keinen Sinn
97         //der Frm muss dann halt Probehalber verschoben werden (Wenn ueberhaupt
98         //etwas Platz zur Verfuegung steht).
99 
100         //Die FixSize der Umgebungen in denen Cntnts herumlungern ist immer
101         //Die Breite.
102 
103         //Wenn mehr als ein Blatt zurueckgegangen wurde (z.B. ueberspringen
104         //von Leerseiten), so muss in jedemfall gemoved werden - sonst wuerde,
105         //falls der Frm nicht in das Blatt passt, nicht mehr auf die
106         //dazwischenliegenden Blaetter geachtet werden.
107         sal_uInt8 nMoveAnyway = 0;
108         SwPageFrm * const pNewPage = pNewUpper->FindPageFrm();
109         SwPageFrm *pOldPage = FindPageFrm();
110 
111         if ( SwFlowFrm::IsMoveBwdJump() )
112             return sal_True;
113 
114         if( IsInFtn() && IsInSct() )
115         {
116             SwFtnFrm* pFtn = FindFtnFrm();
117             SwSectionFrm* pMySect = pFtn->FindSctFrm();
118             if( pMySect && pMySect->IsFtnLock() )
119             {
120                 SwSectionFrm *pSect = pNewUpper->FindSctFrm();
121                 while( pSect && pSect->IsInFtn() )
122                     pSect = pSect->GetUpper()->FindSctFrm();
123                 ASSERT( pSect, "Escaping footnote" );
124                 if( pSect != pMySect )
125                     return sal_False;
126             }
127         }
128         SWRECTFN( this )
129         SWRECTFNX( pNewUpper )
130         if( Abs( (pNewUpper->Prt().*fnRectX->fnGetWidth)() -
131                  (GetUpper()->Prt().*fnRect->fnGetWidth)() ) > 1 )
132             nMoveAnyway = 2; // Damit kommt nur noch ein _WouldFit mit Umhaengen in Frage
133 
134         // OD 2004-05-26 #i25904# - do *not* move backward,
135         // if <nMoveAnyway> equals 3 and no space is left in new upper.
136         nMoveAnyway |= BwdMoveNecessary( pOldPage, Frm() );
137         {
138             const IDocumentSettingAccess* pIDSA = pNewPage->GetFmt()->getIDocumentSettingAccess();
139             SwTwips nSpace = 0;
140             SwRect aRect( pNewUpper->Prt() );
141             aRect.Pos() += pNewUpper->Frm().Pos();
142             const SwFrm *pPrevFrm = pNewUpper->Lower();
143             while ( pPrevFrm )
144             {
145                 SwTwips nNewTop = (pPrevFrm->Frm().*fnRectX->fnGetBottom)();
146                 // OD 2004-03-01 #106629#:
147                 // consider lower spacing of last frame in a table cell
148                 {
149                     // check, if last frame is inside table and if it includes
150                     // its lower spacing.
151                     if ( !pPrevFrm->GetNext() && pPrevFrm->IsInTab() &&
152                          pIDSA->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS) )
153                     {
154                         const SwFrm* pLastFrm = pPrevFrm;
155                         // if last frame is a section, take its last content
156                         if ( pPrevFrm->IsSctFrm() )
157                         {
158                             pLastFrm = static_cast<const SwSectionFrm*>(pPrevFrm)->FindLastCntnt();
159                             if ( pLastFrm &&
160                                  pLastFrm->FindTabFrm() != pPrevFrm->FindTabFrm() )
161                             {
162                                 pLastFrm = pLastFrm->FindTabFrm();
163                             }
164                         }
165 
166                         if ( pLastFrm )
167                         {
168                             SwBorderAttrAccess aAccess( SwFrm::GetCache(), pLastFrm );
169                             const SwBorderAttrs& rAttrs = *aAccess.Get();
170                             nNewTop -= rAttrs.GetULSpace().GetLower();
171                         }
172                     }
173                 }
174                 (aRect.*fnRectX->fnSetTop)( nNewTop );
175 
176                 pPrevFrm = pPrevFrm->GetNext();
177             }
178 
179             nMoveAnyway |= BwdMoveNecessary( pNewPage, aRect);
180 
181             //determine space left in new upper frame
182             nSpace = (aRect.*fnRectX->fnGetHeight)();
183             const ViewShell *pSh = pNewUpper->getRootFrm()->GetCurrShell();
184             if ( IsInFtn() ||
185                  (pSh && pSh->GetViewOptions()->getBrowseMode()) ||
186                  pNewUpper->IsCellFrm() ||
187                  ( pNewUpper->IsInSct() && ( pNewUpper->IsSctFrm() ||
188                    ( pNewUpper->IsColBodyFrm() &&
189                      !pNewUpper->GetUpper()->GetPrev() &&
190                      !pNewUpper->GetUpper()->GetNext() ) ) ) )
191                 nSpace += pNewUpper->Grow( LONG_MAX, sal_True );
192 
193             if ( nMoveAnyway < 3 )
194             {
195                 if ( nSpace )
196                 {
197                     //Keine Beruecksichtigung der Fussnoten die an dem Absatz
198                     //kleben, denn dies wuerde extrem unuebersichtlichen Code
199                     //beduerfen (wg. Beruecksichtung der Breiten und vor allem
200                     //der Flys, die ja wieder Einfluss auf die Fussnoten nehmen...).
201 
202                     // _WouldFit kann bei gleicher Breite und _nur_ selbst verankerten Flys
203                     // befragt werden.
204                     // _WouldFit kann auch gefragt werden, wenn _nur_ fremdverankerte Flys vorliegen,
205                     // dabei ist sogar die Breite egal, da ein TestFormat in der neuen Umgebung
206                     // vorgenommen wird.
207                     // --> OD 2007-11-26 #b6614158#
208                     const sal_uInt8 nBwdMoveNecessaryResult =
209                                             BwdMoveNecessary( pNewPage, aRect);
210                     const bool bObjsInNewUpper( nBwdMoveNecessaryResult == 2 ||
211                                                 nBwdMoveNecessaryResult == 3 );
212 
213                     return _WouldFit( nSpace, pNewUpper, nMoveAnyway == 2,
214                                       bObjsInNewUpper );
215                     // <--
216                 }
217                 //Bei einem spaltigen Bereichsfrischling kann _WouldFit kein
218                 //brauchbares Ergebnis liefern, also muessen wir wirklich
219                 //zurueckfliessen
220                 else if( pNewUpper->IsInSct() && pNewUpper->IsColBodyFrm() &&
221                     !(pNewUpper->Prt().*fnRectX->fnGetWidth)() &&
222                     ( pNewUpper->GetUpper()->GetPrev() ||
223                       pNewUpper->GetUpper()->GetNext() ) )
224                     return sal_True;
225                 else
226                     return sal_False; // Kein Platz, dann ist es sinnlos, zurueckzufliessen
227             }
228             else
229             {
230                 // OD 2004-05-26 #i25904# - check for space left in new upper
231                 if ( nSpace )
232                     return sal_True;
233                 else
234                     return sal_False;
235             }
236         }
237     }
238     return  sal_False;
239 }
240 
241 //------------------------------------------------------------------------
242 //              Calc-Methoden
243 //------------------------------------------------------------------------
244 
245 /*************************************************************************
246 |*
247 |*  SwFrm::Prepare()
248 |*
249 |*  Beschreibung        Bereitet den Frm auf die 'Formatierung' (MakeAll())
250 |*      vor. Diese Methode dient dazu auf dem Stack Platz einzusparen,
251 |*      denn zur Positionsberechnung des Frm muss sichergestellt sein, dass
252 |*      die Position von Upper und Prev gueltig sind, mithin also ein
253 |*      rekursiver Aufruf (Schleife waere relativ teuer, da selten notwendig).
254 |*      Jeder Aufruf von MakeAll verbraucht aber ca. 500Byte Stack -
255 |*      das Ende ist leicht abzusehen. _Prepare benoetigt nur wenig Stack,
256 |*      deshalb solle der Rekursive Aufruf hier kein Problem sein.
257 |*      Ein weiterer Vorteil ist, das eines schoenen Tages das _Prepare und
258 |*      damit die Formatierung von Vorgaengern umgangen werden kann.
259 |*      So kann evtl. mal 'schnell' an's Dokumentende gesprungen werden.
260 |*  Ersterstellung      MA ??
261 |*  Letzte Aenderung    MA 13. Dec. 93
262 |*
263 |*************************************************************************/
264 //Zwei kleine Freundschaften werden hier zu einem Geheimbund.
265 inline void PrepareLock( SwFlowFrm *pTab )
266 {
267     pTab->LockJoin();
268 }
269 inline void PrepareUnlock( SwFlowFrm *pTab )
270 {
271     pTab->UnlockJoin();
272 
273 }
274 
275 // hopefully, one day this function simply will return 'false'
276 bool lcl_IsCalcUpperAllowed( const SwFrm& rFrm )
277 {
278     return !rFrm.GetUpper()->IsSctFrm() &&
279            !rFrm.GetUpper()->IsFooterFrm() &&
280            // --> OD 2004-11-02 #i23129#, #i36347# - no format of upper Writer fly frame
281            !rFrm.GetUpper()->IsFlyFrm() &&
282            // <--
283            !( rFrm.GetUpper()->IsTabFrm() && rFrm.GetUpper()->GetUpper()->IsInTab() ) &&
284            !( rFrm.IsTabFrm() && rFrm.GetUpper()->IsInTab() );
285 }
286 
287 void SwFrm::PrepareMake()
288 {
289     StackHack aHack;
290     if ( GetUpper() )
291     {
292         if ( lcl_IsCalcUpperAllowed( *this ) )
293             GetUpper()->Calc();
294         ASSERT( GetUpper(), ":-( Layoutgeruest wackelig (Upper wech)." );
295         if ( !GetUpper() )
296             return;
297 
298         const sal_Bool bCnt = IsCntntFrm();
299         const sal_Bool bTab = IsTabFrm();
300         sal_Bool bNoSect = IsInSct();
301         sal_Bool bOldTabLock = sal_False, bFoll = sal_False;
302         SwFlowFrm* pThis = bCnt ? (SwCntntFrm*)this : NULL;
303 
304         if ( bTab )
305         {
306             pThis = (SwTabFrm*)this;
307             bOldTabLock = ((SwTabFrm*)this)->IsJoinLocked();
308             ::PrepareLock( (SwTabFrm*)this );
309             bFoll = pThis->IsFollow();
310         }
311         else if( IsSctFrm() )
312         {
313             pThis = (SwSectionFrm*)this;
314             bFoll = pThis->IsFollow();
315             bNoSect = sal_False;
316         }
317         else if ( bCnt && sal_True == (bFoll = pThis->IsFollow()) &&
318              GetPrev() )
319         {
320             //Wenn der Master gereade ein CalcFollow ruft braucht die Kette
321             //nicht durchlaufen werden. Das spart Zeit und vermeidet Probleme.
322             if ( ((SwTxtFrm*)((SwTxtFrm*)this)->FindMaster())->IsLocked() )
323             {
324                 MakeAll();
325                 return;
326             }
327         }
328 
329         // --> OD 2005-03-04 #i44049# - no format of previous frame, if current
330         // frame is a table frame and its previous frame wants to keep with it.
331         const bool bFormatPrev = !bTab ||
332                                  !GetPrev() ||
333                                  !GetPrev()->GetAttrSet()->GetKeep().GetValue();
334         if ( bFormatPrev )
335         {
336             SwFrm *pFrm = GetUpper()->Lower();
337             while ( pFrm != this )
338             {
339                 ASSERT( pFrm, ":-( Layoutgeruest wackelig (this not found)." );
340                 if ( !pFrm )
341                     return; //Oioioioi ...
342 
343                 if ( !pFrm->IsValid() )
344                 {
345                     //Ein kleiner Eingriff der hoffentlich etwas zur Verbesserung
346                     //der Stabilitaet beitraegt:
347                     //Wenn ich Follow _und_ Nachbar eines Frms vor mir bin,
348                     //so wuerde dieser mich beim Formatieren deleten; wie jeder
349                     //leicht sehen kann waere dies eine etwas unuebersichtliche
350                     //Situation die es zu vermeiden gilt.
351                     if ( bFoll && pFrm->IsFlowFrm() &&
352                          (SwFlowFrm::CastFlowFrm(pFrm))->IsAnFollow( pThis ) )
353                         break;
354 
355     //MA: 24. Mar. 94, Calc wuerde doch nur wieder in ein _Prepare laufen und so
356     //die ganze Kette nocheinmal abhuenern.
357     //              pFrm->Calc();
358                     pFrm->MakeAll();
359                     if( IsSctFrm() && !((SwSectionFrm*)this)->GetSection() )
360                         break;
361                 }
362                 //Die Kette kann bei CntntFrms waehrend des durchlaufens
363                 //aufgebrochen werden, deshalb muss der Nachfolger etwas
364                 //umstaendlich ermittelt werden. However, irgendwann _muss_
365                 //ich wieder bei mir selbst ankommen.
366                 pFrm = pFrm->FindNext();
367 
368                 //Wenn wir in einem SectionFrm gestartet sind, koennen wir durch die
369                 //MakeAll-Aufrufe in einen Section-Follow gewandert sein.
370                 //FindNext liefert allerdings den SectionFrm, nicht seinen Inhalt.
371                 // => wir finden uns selbst nicht mehr!
372                 if( bNoSect && pFrm && pFrm->IsSctFrm() )
373                 {
374                     SwFrm* pCnt = ((SwSectionFrm*)pFrm)->ContainsAny();
375                     if( pCnt )
376                         pFrm = pCnt;
377                 }
378             }
379             ASSERT( GetUpper(), "Layoutgeruest wackelig (Upper wech II)." );
380             if ( !GetUpper() )
381                 return;
382 
383             if ( lcl_IsCalcUpperAllowed( *this ) )
384                 GetUpper()->Calc();
385 
386             ASSERT( GetUpper(), "Layoutgeruest wackelig (Upper wech III)." );
387         }
388 
389         if ( bTab && !bOldTabLock )
390             ::PrepareUnlock( (SwTabFrm*)this );
391     }
392     MakeAll();
393 }
394 
395 void SwFrm::OptPrepareMake()
396 {
397     // --> OD 2004-11-02 #i23129#, #i36347# - no format of upper Writer fly frame
398     if ( GetUpper() && !GetUpper()->IsFooterFrm() &&
399          !GetUpper()->IsFlyFrm() )
400     // <--
401     {
402         GetUpper()->Calc();
403         ASSERT( GetUpper(), ":-( Layoutgeruest wackelig (Upper wech)." );
404         if ( !GetUpper() )
405             return;
406     }
407     if ( GetPrev() && !GetPrev()->IsValid() )
408         PrepareMake();
409     else
410     {
411         StackHack aHack;
412         MakeAll();
413     }
414 }
415 
416 
417 
418 void SwFrm::PrepareCrsr()
419 {
420     StackHack aHack;
421     if( GetUpper() && !GetUpper()->IsSctFrm() )
422     {
423         GetUpper()->PrepareCrsr();
424         GetUpper()->Calc();
425 
426         ASSERT( GetUpper(), ":-( Layoutgeruest wackelig (Upper wech)." );
427         if ( !GetUpper() )
428             return;
429 
430         const sal_Bool bCnt = IsCntntFrm();
431         const sal_Bool bTab = IsTabFrm();
432         sal_Bool bNoSect = IsInSct();
433 
434         sal_Bool bOldTabLock = sal_False, bFoll;
435         SwFlowFrm* pThis = bCnt ? (SwCntntFrm*)this : NULL;
436 
437         if ( bTab )
438         {
439             bOldTabLock = ((SwTabFrm*)this)->IsJoinLocked();
440             ::PrepareLock( (SwTabFrm*)this );
441             pThis = (SwTabFrm*)this;
442         }
443         else if( IsSctFrm() )
444         {
445             pThis = (SwSectionFrm*)this;
446             bNoSect = sal_False;
447         }
448         bFoll = pThis && pThis->IsFollow();
449 
450         SwFrm *pFrm = GetUpper()->Lower();
451         while ( pFrm != this )
452         {
453             ASSERT( pFrm, ":-( Layoutgeruest wackelig (this not found)." );
454             if ( !pFrm )
455                 return; //Oioioioi ...
456 
457             if ( !pFrm->IsValid() )
458             {
459                 //Ein kleiner Eingriff der hoffentlich etwas zur Verbesserung
460                 //der Stabilitaet beitraegt:
461                 //Wenn ich Follow _und_ Nachbar eines Frms vor mir bin,
462                 //so wuerde dieser mich beim Formatieren deleten; wie jeder
463                 //leicht sehen kann waere dies eine etwas unuebersichtliche
464                 //Situation die es zu vermeiden gilt.
465                 if ( bFoll && pFrm->IsFlowFrm() &&
466                      (SwFlowFrm::CastFlowFrm(pFrm))->IsAnFollow( pThis ) )
467                     break;
468 
469                 pFrm->MakeAll();
470             }
471             //Die Kette kann bei CntntFrms waehrend des durchlaufens
472             //aufgebrochen werden, deshalb muss der Nachfolger etwas
473             //umstaendlich ermittelt werden. However, irgendwann _muss_
474             //ich wieder bei mir selbst ankommen.
475             pFrm = pFrm->FindNext();
476             if( bNoSect && pFrm && pFrm->IsSctFrm() )
477             {
478                 SwFrm* pCnt = ((SwSectionFrm*)pFrm)->ContainsAny();
479                 if( pCnt )
480                     pFrm = pCnt;
481             }
482         }
483         ASSERT( GetUpper(), "Layoutgeruest wackelig (Upper wech II)." );
484         if ( !GetUpper() )
485             return;
486 
487         GetUpper()->Calc();
488 
489         ASSERT( GetUpper(), "Layoutgeruest wackelig (Upper wech III)." );
490 
491         if ( bTab && !bOldTabLock )
492             ::PrepareUnlock( (SwTabFrm*)this );
493     }
494     Calc();
495 }
496 
497 /*************************************************************************
498 |*
499 |*  SwFrm::MakePos()
500 |*
501 |*  Ersterstellung      MA ??
502 |*  Letzte Aenderung    MA 24. May. 93
503 |*
504 |*************************************************************************/
505 
506 // Hier wird GetPrev() zurueckgegeben, allerdings werden
507 // dabei leere SectionFrms ueberlesen
508 SwFrm* lcl_Prev( SwFrm* pFrm, sal_Bool bSectPrv = sal_True )
509 {
510     SwFrm* pRet = pFrm->GetPrev();
511     if( !pRet && pFrm->GetUpper() && pFrm->GetUpper()->IsSctFrm() &&
512         bSectPrv && !pFrm->IsColumnFrm() )
513         pRet = pFrm->GetUpper()->GetPrev();
514     while( pRet && pRet->IsSctFrm() &&
515            !((SwSectionFrm*)pRet)->GetSection() )
516         pRet = pRet->GetPrev();
517     return pRet;
518 }
519 
520 SwFrm* lcl_NotHiddenPrev( SwFrm* pFrm )
521 {
522     SwFrm *pRet = pFrm;
523     do
524     {
525         pRet = lcl_Prev( pRet );
526     } while ( pRet && pRet->IsTxtFrm() && ((SwTxtFrm*)pRet)->IsHiddenNow() );
527     return pRet;
528 }
529 
530 void SwFrm::MakePos()
531 {
532     if ( !bValidPos )
533     {
534         bValidPos = sal_True;
535         sal_Bool bUseUpper = sal_False;
536         SwFrm* pPrv = lcl_Prev( this );
537         if ( pPrv &&
538              ( !pPrv->IsCntntFrm() ||
539                ( ((SwCntntFrm*)pPrv)->GetFollow() != this ) )
540            )
541         {
542             if ( !StackHack::IsLocked() &&
543                  ( !IsInSct() || IsSctFrm() ) &&
544                  !pPrv->IsSctFrm() &&
545                  !pPrv->GetAttrSet()->GetKeep().GetValue()
546                )
547             {
548                 pPrv->Calc();   //hierbei kann der Prev verschwinden!
549             }
550             else if ( pPrv->Frm().Top() == 0 )
551             {
552                 bUseUpper = sal_True;
553             }
554         }
555 
556         pPrv = lcl_Prev( this, sal_False );
557         sal_uInt16 nMyType = GetType();
558         SWRECTFN( ( IsCellFrm() && GetUpper() ? GetUpper() : this  ) )
559         if ( !bUseUpper && pPrv )
560         {
561             aFrm.Pos( pPrv->Frm().Pos() );
562             if( FRM_NEIGHBOUR & nMyType )
563             {
564                 sal_Bool bR2L = IsRightToLeft();
565                 if( bR2L )
566                     (aFrm.*fnRect->fnSetPosX)( (aFrm.*fnRect->fnGetLeft)() -
567                                                (aFrm.*fnRect->fnGetWidth)() );
568                 else
569                     (aFrm.*fnRect->fnSetPosX)( (aFrm.*fnRect->fnGetLeft)() +
570                                           (pPrv->Frm().*fnRect->fnGetWidth)() );
571 
572                 // cells may now leave their uppers
573                 if( bVert && FRM_CELL & nMyType && !bReverse )
574                     aFrm.Pos().X() -= aFrm.Width() -pPrv->Frm().Width();
575             }
576             else if( bVert && FRM_NOTE_VERT & nMyType )
577             {
578                 if( bReverse )
579                     aFrm.Pos().X() += pPrv->Frm().Width();
580                 else
581                     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
582                 {
583                     if ( bVertL2R )
584                         aFrm.Pos().X() += pPrv->Frm().Width();
585                     else
586                         aFrm.Pos().X() -= aFrm.Width();
587                 }
588             }
589             else
590                 aFrm.Pos().Y() += pPrv->Frm().Height();
591         }
592         else if ( GetUpper() )
593         {
594             // OD 15.10.2002 #103517# - add safeguard for <SwFooterFrm::Calc()>
595             // If parent frame is a footer frame and its <ColLocked()>, then
596             // do *not* calculate it.
597             // NOTE: Footer frame is <ColLocked()> during its
598             //     <FormatSize(..)>, which is called from <Format(..)>, which
599             //     is called from <MakeAll()>, which is called from <Calc()>.
600             // --> OD 2005-11-17 #i56850#
601             // - no format of upper Writer fly frame, which is anchored
602             //   at-paragraph or at-character.
603             if ( !GetUpper()->IsTabFrm() &&
604                  !( IsTabFrm() && GetUpper()->IsInTab() ) &&
605                  !GetUpper()->IsSctFrm() &&
606                  !dynamic_cast<SwFlyAtCntFrm*>(GetUpper()) &&
607                  !( GetUpper()->IsFooterFrm() &&
608                     GetUpper()->IsColLocked() )
609                )
610             {
611                 GetUpper()->Calc();
612             }
613             // <--
614             pPrv = lcl_Prev( this, sal_False );
615             if ( !bUseUpper && pPrv )
616             {
617                 aFrm.Pos( pPrv->Frm().Pos() );
618                 if( FRM_NEIGHBOUR & nMyType )
619                 {
620                     sal_Bool bR2L = IsRightToLeft();
621                     if( bR2L )
622                         (aFrm.*fnRect->fnSetPosX)( (aFrm.*fnRect->fnGetLeft)() -
623                                                  (aFrm.*fnRect->fnGetWidth)() );
624                     else
625                         (aFrm.*fnRect->fnSetPosX)( (aFrm.*fnRect->fnGetLeft)() +
626                                           (pPrv->Frm().*fnRect->fnGetWidth)() );
627 
628                     // cells may now leave their uppers
629                     if( bVert && FRM_CELL & nMyType && !bReverse )
630                         aFrm.Pos().X() -= aFrm.Width() -pPrv->Frm().Width();
631                 }
632                 else if( bVert && FRM_NOTE_VERT & nMyType )
633                 {
634                     if( bReverse )
635                         aFrm.Pos().X() += pPrv->Frm().Width();
636                     else
637                         aFrm.Pos().X() -= aFrm.Width();
638                 }
639                 else
640                     aFrm.Pos().Y() += pPrv->Frm().Height();
641             }
642             else
643             {
644                 aFrm.Pos( GetUpper()->Frm().Pos() );
645                 aFrm.Pos() += GetUpper()->Prt().Pos();
646                 if( FRM_NEIGHBOUR & nMyType && IsRightToLeft() )
647                 {
648                     if( bVert )
649                         aFrm.Pos().Y() += GetUpper()->Prt().Height()
650                                           - aFrm.Height();
651                     else
652                         aFrm.Pos().X() += GetUpper()->Prt().Width()
653                                           - aFrm.Width();
654                 }
655                 //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
656                 else if( bVert && !bVertL2R && FRM_NOTE_VERT & nMyType && !bReverse )
657                     aFrm.Pos().X() -= aFrm.Width() - GetUpper()->Prt().Width();
658             }
659         }
660         else
661             aFrm.Pos().X() = aFrm.Pos().Y() = 0;
662         //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
663         if( IsBodyFrm() && bVert && !bVertL2R && !bReverse && GetUpper() )
664             aFrm.Pos().X() += GetUpper()->Prt().Width() - aFrm.Width();
665         bValidPos = sal_True;
666     }
667 }
668 
669 /*************************************************************************
670 |*
671 |*  SwPageFrm::MakeAll()
672 |*
673 |*  Ersterstellung      MA 23. Feb. 93
674 |*  Letzte Aenderung    MA 20. Jul. 98
675 |*
676 |*************************************************************************/
677 // --> OD 2004-07-01 #i28701# - new type <SwSortedObjs>
678 void lcl_CheckObjects( SwSortedObjs* pSortedObjs, SwFrm* pFrm, long& rBot )
679 {
680     //Und dann kann es natuerlich noch Absatzgebundene
681     //Rahmen geben, die unterhalb ihres Absatzes stehen.
682     long nMax = 0;
683     for ( sal_uInt16 i = 0; i < pSortedObjs->Count(); ++i )
684     {
685         // --> OD 2004-07-01 #i28701# - consider changed type of <SwSortedObjs>
686         // entries.
687         SwAnchoredObject* pObj = (*pSortedObjs)[i];
688         long nTmp = 0;
689         if ( pObj->ISA(SwFlyFrm) )
690         {
691             SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pObj);
692             if( pFly->Frm().Top() != WEIT_WECH &&
693                 ( pFrm->IsPageFrm() ? pFly->IsFlyLayFrm() :
694                   ( pFly->IsFlyAtCntFrm() &&
695                     ( pFrm->IsBodyFrm() ? pFly->GetAnchorFrm()->IsInDocBody() :
696                                           pFly->GetAnchorFrm()->IsInFtn() ) ) ) )
697             {
698                 nTmp = pFly->Frm().Bottom();
699             }
700         }
701         else
702             nTmp = pObj->GetObjRect().Bottom();
703         nMax = Max( nTmp, nMax );
704         // <--
705     }
706     ++nMax; //Unterkante vs. Hoehe!
707     rBot = Max( rBot, nMax );
708 }
709 
710 void SwPageFrm::MakeAll()
711 {
712     PROTOCOL_ENTER( this, PROT_MAKEALL, 0, 0 )
713 
714     const SwRect aOldRect( Frm() );     //Anpassung der Root-Groesse
715     const SwLayNotify aNotify( this );  //uebernimmt im DTor die Benachrichtigung
716     SwBorderAttrAccess *pAccess = 0;
717     const SwBorderAttrs*pAttrs = 0;
718 
719     while ( !bValidPos || !bValidSize || !bValidPrtArea )
720     {
721         if ( !bValidPos )
722         {
723             // PAGES01
724             bValidPos = sal_True; // positioning of the pages is taken care of by the root frame
725         }
726 
727         if ( !bValidSize || !bValidPrtArea )
728         {
729             if ( IsEmptyPage() )
730             {
731                 Frm().Width( 0 );  Prt().Width( 0 );
732                 Frm().Height( 0 ); Prt().Height( 0 );
733                 Prt().Left( 0 );   Prt().Top( 0 );
734                 bValidSize = bValidPrtArea = sal_True;
735             }
736             else
737             {
738                 if ( !pAccess )
739                 {
740                     pAccess = new SwBorderAttrAccess( SwFrm::GetCache(), this );
741                     pAttrs = pAccess->Get();
742                 }
743                 //Bei der BrowseView gelten feste Einstellungen.
744                 ViewShell *pSh = getRootFrm()->GetCurrShell();
745                 if ( pSh && pSh->GetViewOptions()->getBrowseMode() )
746                 {
747                     const Size aBorder = pSh->GetOut()->PixelToLogic( pSh->GetBrowseBorder() );
748                     const long nTop    = pAttrs->CalcTopLine()   + aBorder.Height();
749                     const long nBottom = pAttrs->CalcBottomLine()+ aBorder.Height();
750 
751                     long nWidth = GetUpper() ? ((SwRootFrm*)GetUpper())->GetBrowseWidth() : 0;
752                     if ( nWidth < pSh->GetBrowseWidth() )
753                         nWidth = pSh->GetBrowseWidth();
754                     nWidth += + 2 * aBorder.Width();
755 /*
756                     long nWidth = GetUpper() ? ((SwRootFrm*)GetUpper())->GetBrowseWidth() + 2 * aBorder.Width() : 0;
757                     if ( nWidth < pSh->VisArea().Width() )
758                         nWidth = pSh->VisArea().Width(); */
759 
760                     nWidth = Max( nWidth, 2L * aBorder.Width() + 4L*MM50 );
761                     Frm().Width( nWidth );
762 
763                     SwLayoutFrm *pBody = FindBodyCont();
764                     if ( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrm() )
765                     {
766                         //Fuer Spalten gilt eine feste Hoehe
767                         Frm().Height( pAttrs->GetSize().Height() );
768                     }
769                     else
770                     {
771                         //Fuer Seiten ohne Spalten bestimmt der Inhalt die
772                         //Groesse.
773                         long nBot = Frm().Top() + nTop;
774                         SwFrm *pFrm = Lower();
775                         while ( pFrm )
776                         {
777                             long nTmp = 0;
778                             SwFrm *pCnt = ((SwLayoutFrm*)pFrm)->ContainsAny();
779                             while ( pCnt && (pCnt->GetUpper() == pFrm ||
780                                              ((SwLayoutFrm*)pFrm)->IsAnLower( pCnt )))
781                             {
782                                 nTmp += pCnt->Frm().Height();
783                                 if( pCnt->IsTxtFrm() &&
784                                     ((SwTxtFrm*)pCnt)->IsUndersized() )
785                                     nTmp += ((SwTxtFrm*)pCnt)->GetParHeight()
786                                             - pCnt->Prt().Height();
787                                 else if( pCnt->IsSctFrm() &&
788                                          ((SwSectionFrm*)pCnt)->IsUndersized() )
789                                     nTmp += ((SwSectionFrm*)pCnt)->Undersize();
790                                 pCnt = pCnt->FindNext();
791                             }
792                             // OD 29.10.2002 #97265# - consider invalid body frame properties
793                             if ( pFrm->IsBodyFrm() &&
794                                  ( !pFrm->GetValidSizeFlag() ||
795                                    !pFrm->GetValidPrtAreaFlag() ) &&
796                                  ( pFrm->Frm().Height() < pFrm->Prt().Height() )
797                                )
798                             {
799                                 nTmp = Min( nTmp, pFrm->Frm().Height() );
800                             }
801                             else
802                             {
803                                 // OD 30.10.2002 #97265# - assert invalid lower property
804                                 ASSERT( !(pFrm->Frm().Height() < pFrm->Prt().Height()),
805                                         "SwPageFrm::MakeAll(): Lower with frame height < printing height" );
806                                 nTmp += pFrm->Frm().Height() - pFrm->Prt().Height();
807                             }
808                             if ( !pFrm->IsBodyFrm() )
809                                 nTmp = Min( nTmp, pFrm->Frm().Height() );
810                             nBot += nTmp;
811                             // Hier werden die absatzgebundenen Objekte ueberprueft,
812                             // ob sie ueber den Body/FtnCont hinausragen.
813                             if( pSortedObjs && !pFrm->IsHeaderFrm() &&
814                                 !pFrm->IsFooterFrm() )
815                                 lcl_CheckObjects( pSortedObjs, pFrm, nBot );
816                             pFrm = pFrm->GetNext();
817                         }
818                         nBot += nBottom;
819                         //Und die Seitengebundenen
820                         if ( pSortedObjs )
821                             lcl_CheckObjects( pSortedObjs, this, nBot );
822                         nBot -= Frm().Top();
823                         // --> OD 2004-11-10 #i35143# - If second page frame
824                         // exists, the first page doesn't have to fulfill the
825                         // visible area.
826                         if ( !GetPrev() && !GetNext() )
827                         // <--
828                         {
829                             nBot = Max( nBot, pSh->VisArea().Height() );
830                         }
831                         // --> OD 2004-11-10 #i35143# - Assure, that the page
832                         // doesn't exceed the defined browse height.
833                         Frm().Height( Min( nBot, BROWSE_HEIGHT ) );
834                         // <--
835                     }
836                     Prt().Left ( pAttrs->CalcLeftLine() + aBorder.Width() );
837                     Prt().Top  ( nTop );
838                     Prt().Width( Frm().Width() - ( Prt().Left()
839                         + pAttrs->CalcRightLine() + aBorder.Width() ) );
840                     Prt().Height( Frm().Height() - (nTop + nBottom) );
841                     bValidSize = bValidPrtArea = sal_True;
842                 }
843                 else
844                 {   //FixSize einstellen, bei Seiten nicht vom Upper sondern vom
845                     //Attribut vorgegeben.
846                     Frm().SSize( pAttrs->GetSize() );
847                     Format( pAttrs );
848                 }
849             }
850         }
851     } //while ( !bValidPos || !bValidSize || !bValidPrtArea )
852     delete pAccess;
853 
854     // PAGES01
855     if ( Frm() != aOldRect && GetUpper() )
856         static_cast<SwRootFrm*>(GetUpper())->CheckViewLayout( 0, 0 );
857 
858 #ifdef DBG_UTIL
859     //Der Upper (Root) muss mindestens so breit
860     //sein, dass er die breiteste Seite aufnehmen kann.
861     if ( GetUpper() )
862     {
863         ASSERT( GetUpper()->Prt().Width() >= aFrm.Width(), "Rootsize" );
864     }
865 #endif
866 }
867 
868 /*************************************************************************
869 |*
870 |*  SwLayoutFrm::MakeAll()
871 |*
872 |*  Ersterstellung      MA ??
873 |*  Letzte Aenderung    MA 28. Nov. 95
874 |*
875 |*************************************************************************/
876 
877 
878 void SwLayoutFrm::MakeAll()
879 {
880     PROTOCOL_ENTER( this, PROT_MAKEALL, 0, 0 )
881 
882         //uebernimmt im DTor die Benachrichtigung
883     const SwLayNotify aNotify( this );
884     sal_Bool bVert = IsVertical();
885     //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
886     SwRectFn fnRect = ( IsNeighbourFrm() == bVert )? fnRectHori : ( IsVertLR() ? fnRectVertL2R : fnRectVert );
887 
888     SwBorderAttrAccess *pAccess = 0;
889     const SwBorderAttrs*pAttrs = 0;
890 
891     while ( !bValidPos || !bValidSize || !bValidPrtArea )
892     {
893         if ( !bValidPos )
894             MakePos();
895 
896         if ( GetUpper() )
897         {
898             // NEW TABLES
899             if ( IsLeaveUpperAllowed() )
900             {
901                 if ( !bValidSize )
902                     bValidPrtArea = sal_False;
903             }
904             else
905             {
906                 if ( !bValidSize )
907                 {
908                     //FixSize einstellen, die VarSize wird von Format() nach
909                     //Berechnung der PrtArea eingestellt.
910                     bValidPrtArea = sal_False;
911 
912                     SwTwips nPrtWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)();
913                     if( bVert && ( IsBodyFrm() || IsFtnContFrm() ) )
914                     {
915                         SwFrm* pNxt = GetPrev();
916                         while( pNxt && !pNxt->IsHeaderFrm() )
917                             pNxt = pNxt->GetPrev();
918                         if( pNxt )
919                             nPrtWidth -= pNxt->Frm().Height();
920                         pNxt = GetNext();
921                         while( pNxt && !pNxt->IsFooterFrm() )
922                             pNxt = pNxt->GetNext();
923                         if( pNxt )
924                             nPrtWidth -= pNxt->Frm().Height();
925                     }
926 
927                     const long nDiff = nPrtWidth - (Frm().*fnRect->fnGetWidth)();
928 
929                     if( IsNeighbourFrm() && IsRightToLeft() )
930                         (Frm().*fnRect->fnSubLeft)( nDiff );
931                     else
932                         (Frm().*fnRect->fnAddRight)( nDiff );
933                 }
934                 else
935                 {
936                     // Don't leave your upper
937                     const SwTwips nDeadLine = (GetUpper()->*fnRect->fnGetPrtBottom)();
938                     if( (Frm().*fnRect->fnOverStep)( nDeadLine ) )
939                         bValidSize = sal_False;
940                 }
941             }
942         }
943         if ( !bValidSize || !bValidPrtArea )
944         {
945             if ( !pAccess )
946             {
947                 pAccess = new SwBorderAttrAccess( SwFrm::GetCache(), this );
948                 pAttrs  = pAccess->Get();
949             }
950             Format( pAttrs );
951         }
952     } //while ( !bValidPos || !bValidSize || !bValidPrtArea )
953     if ( pAccess )
954         delete pAccess;
955 }
956 
957 /*************************************************************************
958 |*
959 |*  SwCntntFrm::MakePrtArea()
960 |*
961 |*  Ersterstellung      MA 17. Nov. 92
962 |*  Letzte Aenderung    MA 03. Mar. 96
963 |*
964 |*************************************************************************/
965 
966 sal_Bool SwCntntFrm::MakePrtArea( const SwBorderAttrs &rAttrs )
967 {
968     sal_Bool bSizeChgd = sal_False;
969 
970     if ( !bValidPrtArea )
971     {
972         bValidPrtArea = sal_True;
973 
974         SWRECTFN( this )
975         const sal_Bool bTxtFrm = IsTxtFrm();
976         SwTwips nUpper = 0;
977         if ( bTxtFrm && ((SwTxtFrm*)this)->IsHiddenNow() )
978         {
979             if ( ((SwTxtFrm*)this)->HasFollow() )
980                 ((SwTxtFrm*)this)->JoinFrm();
981 
982             if( (Prt().*fnRect->fnGetHeight)() )
983                 ((SwTxtFrm*)this)->HideHidden();
984             Prt().Pos().X() = Prt().Pos().Y() = 0;
985             (Prt().*fnRect->fnSetWidth)( (Frm().*fnRect->fnGetWidth)() );
986             (Prt().*fnRect->fnSetHeight)( 0 );
987             nUpper = -( (Frm().*fnRect->fnGetHeight)() );
988         }
989         else
990         {
991             //Vereinfachung: CntntFrms sind immer in der Hoehe Variabel!
992 
993             //An der FixSize gibt der umgebende Frame die Groesse vor, die
994             //Raender werden einfach abgezogen.
995             const long nLeft = rAttrs.CalcLeft( this );
996             const long nRight = ((SwBorderAttrs&)rAttrs).CalcRight( this );
997             (this->*fnRect->fnSetXMargins)( nLeft, nRight );
998 
999             ViewShell *pSh = getRootFrm()->GetCurrShell();
1000             SwTwips nWidthArea;
1001             if( pSh && 0!=(nWidthArea=(pSh->VisArea().*fnRect->fnGetWidth)()) &&
1002                 GetUpper()->IsPageBodyFrm() &&  // nicht dagegen bei BodyFrms in Columns
1003                 pSh->GetViewOptions()->getBrowseMode() )
1004             {
1005                 //Nicht ueber die Kante des sichbaren Bereiches hinausragen.
1006                 //Die Seite kann breiter sein, weil es Objekte mit "ueberbreite"
1007                 //geben kann (RootFrm::ImplCalcBrowseWidth())
1008                 long nMinWidth = 0;
1009 
1010                 for (sal_uInt16 i = 0; GetDrawObjs() && i < GetDrawObjs()->Count();++i)
1011                 {
1012                     // --> OD 2004-07-01 #i28701# - consider changed type of
1013                     // <SwSortedObjs> entries
1014                     SwAnchoredObject* pObj = (*GetDrawObjs())[i];
1015                     const SwFrmFmt& rFmt = pObj->GetFrmFmt();
1016                     const sal_Bool bFly = pObj->ISA(SwFlyFrm);
1017                     if ((bFly && (WEIT_WECH == pObj->GetObjRect().Width()))
1018                         || rFmt.GetFrmSize().GetWidthPercent())
1019                     {
1020                         continue;
1021                     }
1022 
1023                     if ( FLY_AS_CHAR == rFmt.GetAnchor().GetAnchorId() )
1024                     {
1025                         nMinWidth = Max( nMinWidth,
1026                                          bFly ? rFmt.GetFrmSize().GetWidth()
1027                                               : pObj->GetObjRect().Width() );
1028                     }
1029                     // <--
1030                 }
1031 
1032                 const Size aBorder = pSh->GetOut()->PixelToLogic( pSh->GetBrowseBorder() );
1033                 long nWidth = nWidthArea - 2 * ( IsVertical() ? aBorder.Height() : aBorder.Width() );
1034                 nWidth -= (Prt().*fnRect->fnGetLeft)();
1035                 nWidth -= rAttrs.CalcRightLine();
1036                 nWidth = Max( nMinWidth, nWidth );
1037                 (Prt().*fnRect->fnSetWidth)( Min( nWidth,
1038                                             (Prt().*fnRect->fnGetWidth)() ) );
1039             }
1040 
1041             if ( (Prt().*fnRect->fnGetWidth)() <= MINLAY )
1042             {
1043                 //Die PrtArea sollte schon wenigstens MINLAY breit sein, passend
1044                 //zu den Minimalwerten des UI
1045                 (Prt().*fnRect->fnSetWidth)( Min( long(MINLAY),
1046                                              (Frm().*fnRect->fnGetWidth)() ) );
1047                 SwTwips nTmp = (Frm().*fnRect->fnGetWidth)() -
1048                                (Prt().*fnRect->fnGetWidth)();
1049                 if( (Prt().*fnRect->fnGetLeft)() > nTmp )
1050                     (Prt().*fnRect->fnSetLeft)( nTmp );
1051             }
1052 
1053             //Fuer die VarSize gelten folgende Regeln:
1054             //1. Der erste einer Kette hat keinen Rand nach oben
1055             //2. Nach unten gibt es nie einen Rand
1056             //3. Der Rand nach oben ist das Maximum aus dem Abstand des
1057             //   Prev nach unten und dem eigenen Abstand nach oben.
1058             //Die drei Regeln werden auf die Berechnung der Freiraeume, die von
1059             //UL- bzw. LRSpace vorgegeben werden, angewand. Es gibt in alle
1060             //Richtungen jedoch ggf. trotzdem einen Abstand; dieser wird durch
1061             //Umrandung und/oder Schatten vorgegeben.
1062             //4. Der Abstand fuer TextFrms entspricht mindestens dem Durchschuss
1063 
1064             nUpper = CalcUpperSpace( &rAttrs, NULL );
1065 
1066             // OD 2004-03-02 #106629# - use new method <CalcLowerSpace(..)>
1067             SwTwips nLower = CalcLowerSpace( &rAttrs );
1068 //            // in balanced columned section frames we do not want the
1069 //            // common border
1070 //            sal_Bool bCommonBorder = sal_True;
1071 //            if ( IsInSct() && GetUpper()->IsColBodyFrm() )
1072 //            {
1073 //                const SwSectionFrm* pSct = FindSctFrm();
1074 //                bCommonBorder = pSct->GetFmt()->GetBalancedColumns().GetValue();
1075 //            }
1076 //            SwTwips nLower = bCommonBorder ?
1077 //                             rAttrs.GetBottomLine( this ) :
1078 //                             rAttrs.CalcBottomLine();
1079 
1080             (Prt().*fnRect->fnSetPosY)( (!bVert || bReverse) ? nUpper : nLower);
1081             nUpper += nLower;
1082             nUpper -= (Frm().*fnRect->fnGetHeight)() -
1083                       (Prt().*fnRect->fnGetHeight)();
1084         }
1085         //Wenn Unterschiede zwischen Alter und neuer Groesse,
1086         //Grow() oder Shrink() rufen
1087         if ( nUpper )
1088         {
1089             if ( nUpper > 0 )
1090                 GrowFrm( nUpper );
1091             else
1092                 ShrinkFrm( -nUpper );
1093             bSizeChgd = sal_True;
1094         }
1095     }
1096     return bSizeChgd;
1097 }
1098 
1099 /*************************************************************************
1100 |*
1101 |*  SwCntntFrm::MakeAll()
1102 |*
1103 |*  Ersterstellung      MA ??
1104 |*  Letzte Aenderung    MA 16. Dec. 96
1105 |*
1106 |*************************************************************************/
1107 
1108 #define STOP_FLY_FORMAT 10
1109 // --> OD 2006-09-25 #b6448963# - loop prevention
1110 const int cnStopFormat = 15;
1111 // <--
1112 
1113 inline void ValidateSz( SwFrm *pFrm )
1114 {
1115     if ( pFrm )
1116     {
1117         pFrm->bValidSize = sal_True;
1118         pFrm->bValidPrtArea = sal_True;
1119     }
1120 }
1121 
1122 void SwCntntFrm::MakeAll()
1123 {
1124     ASSERT( GetUpper(), "keinen Upper?" );
1125     ASSERT( IsTxtFrm(), "MakeAll(), NoTxt" );
1126 
1127     if ( !IsFollow() && StackHack::IsLocked() )
1128         return;
1129 
1130     if ( IsJoinLocked() )
1131         return;
1132 
1133     ASSERT( !((SwTxtFrm*)this)->IsSwapped(), "Calculation of a swapped frame" );
1134 
1135     StackHack aHack;
1136 
1137     if ( ((SwTxtFrm*)this)->IsLocked() )
1138     {
1139         ASSERT( sal_False, "Format fuer gelockten TxtFrm." );
1140         return;
1141     }
1142 
1143     LockJoin();
1144     long nFormatCount = 0;
1145     // --> OD 2006-09-25 #b6448963# - loop prevention
1146     int nConsequetiveFormatsWithoutChange = 0;
1147     // <--
1148     PROTOCOL_ENTER( this, PROT_MAKEALL, 0, 0 )
1149 
1150 #ifdef DBG_UTIL
1151     const SwDoc *pDoc = GetAttrSet()->GetDoc();
1152     if( pDoc )
1153     {
1154         static sal_Bool bWarn = sal_False;
1155         if( pDoc->InXMLExport() )
1156         {
1157             ASSERT( bWarn, "Formatting during XML-export!" );
1158             bWarn = sal_True;
1159         }
1160         else
1161             bWarn = sal_False;
1162     }
1163 #endif
1164 
1165     //uebernimmt im DTor die Benachrichtigung
1166     SwCntntNotify *pNotify = new SwCntntNotify( this );
1167 
1168     sal_Bool    bMakePage   = sal_True;     //solange sal_True kann eine neue Seite
1169                                     //angelegt werden (genau einmal)
1170     sal_Bool    bMovedBwd   = sal_False;    //Wird sal_True wenn der Frame zurueckfliesst
1171     sal_Bool    bMovedFwd   = sal_False;    //solange sal_False kann der Frm zurueck-
1172                                     //fliessen (solange, bis er einmal
1173                                     //vorwaerts ge'moved wurde).
1174     sal_Bool    bFormatted  = sal_False;    //Fuer die Witwen und Waisen Regelung
1175                                     //wird der letzte CntntFrm einer Kette
1176                                     //u.U. zum Formatieren angeregt, dies
1177                                     //braucht nur einmal zu passieren.
1178                                     //Immer wenn der Frm gemoved wird muss
1179                                     //das Flag zurueckgesetzt werden.
1180     sal_Bool    bMustFit    = sal_False;    //Wenn einmal die Notbremse gezogen wurde,
1181                                     //werden keine anderen Prepares mehr
1182                                     //abgesetzt.
1183     sal_Bool    bFitPromise = sal_False;    //Wenn ein Absatz nicht passte, mit WouldFit
1184                                     //aber verspricht, dass er sich passend
1185                                     //einstellt wird dieses Flag gesetzt.
1186                                     //Wenn er dann sein Versprechen nicht haelt,
1187                                     //kann kontrolliert verfahren werden.
1188     sal_Bool bMoveable;
1189     const sal_Bool bFly = IsInFly();
1190     const sal_Bool bTab = IsInTab();
1191     const sal_Bool bFtn = IsInFtn();
1192     const sal_Bool bSct = IsInSct();
1193     Point aOldFrmPos;               //Damit bei Turnarounds jew. mit der
1194     Point aOldPrtPos;               //letzten Pos verglichen und geprueft
1195                                     //werden kann, ob ein Prepare sinnvoll ist.
1196 
1197     SwBorderAttrAccess aAccess( SwFrm::GetCache(), this );
1198     const SwBorderAttrs &rAttrs = *aAccess.Get();
1199 
1200     // OD 2004-02-26 #i25029#
1201     if ( !IsFollow() && rAttrs.JoinedWithPrev( *(this) ) )
1202     {
1203         pNotify->SetBordersJoinedWithPrev();
1204     }
1205 
1206     const sal_Bool bKeep = IsKeep( rAttrs.GetAttrSet() );
1207 
1208     SwSaveFtnHeight *pSaveFtn = 0;
1209     if ( bFtn )
1210     {
1211         SwFtnFrm *pFtn = FindFtnFrm();
1212         SwSectionFrm* pSct = pFtn->FindSctFrm();
1213         if ( !((SwTxtFrm*)pFtn->GetRef())->IsLocked() )
1214         {
1215             SwFtnBossFrm* pBoss = pFtn->GetRef()->FindFtnBossFrm(
1216                                     pFtn->GetAttr()->GetFtn().IsEndNote() );
1217             if( !pSct || pSct->IsColLocked() || !pSct->Growable() )
1218                 pSaveFtn = new SwSaveFtnHeight( pBoss,
1219                     ((SwTxtFrm*)pFtn->GetRef())->GetFtnLine( pFtn->GetAttr() ) );
1220         }
1221     }
1222 
1223     // --> OD 2008-08-12 #b6732519#
1224     if ( GetUpper()->IsSctFrm() &&
1225          HasFollow() &&
1226          GetFollow()->GetFrm() == GetNext() )
1227     {
1228         dynamic_cast<SwTxtFrm*>(this)->JoinFrm();
1229     }
1230     // <--
1231 
1232     // --> OD 2004-06-23 #i28701# - move master forward, if it has to move,
1233     // because of its object positioning.
1234     if ( !static_cast<SwTxtFrm*>(this)->IsFollow() )
1235     {
1236         sal_uInt32 nToPageNum = 0L;
1237         const bool bMoveFwdByObjPos = SwLayouter::FrmMovedFwdByObjPos(
1238                                                     *(GetAttrSet()->GetDoc()),
1239                                                     *(static_cast<SwTxtFrm*>(this)),
1240                                                     nToPageNum );
1241         // --> OD 2006-01-27 #i58182#
1242         // Also move a paragraph forward, which is the first one inside a table cell.
1243         if ( bMoveFwdByObjPos &&
1244              FindPageFrm()->GetPhyPageNum() < nToPageNum &&
1245              ( lcl_Prev( this ) ||
1246                GetUpper()->IsCellFrm() ||
1247                ( GetUpper()->IsSctFrm() &&
1248                  GetUpper()->GetUpper()->IsCellFrm() ) ) &&
1249              IsMoveable() )
1250         {
1251             bMovedFwd = sal_True;
1252             MoveFwd( bMakePage, sal_False );
1253         }
1254         // <--
1255     }
1256     // <--
1257 
1258     //Wenn ein Follow neben seinem Master steht und nicht passt, kann er
1259     //gleich verschoben werden.
1260     if ( lcl_Prev( this ) && ((SwTxtFrm*)this)->IsFollow() && IsMoveable() )
1261     {
1262         bMovedFwd = sal_True;
1263         // OD 2004-03-02 #106629# - If follow frame is in table, it's master
1264         // will be the last in the current table cell. Thus, invalidate the
1265         // printing area of the master,
1266         if ( IsInTab() )
1267         {
1268             lcl_Prev( this )->InvalidatePrt();
1269         }
1270         MoveFwd( bMakePage, sal_False );
1271     }
1272 
1273     // OD 08.11.2002 #104840# - check footnote content for forward move.
1274     // If a content of a footnote is on a prior page/column as its invalid
1275     // reference, it can be moved forward.
1276     if ( bFtn && !bValidPos )
1277     {
1278         SwFtnFrm* pFtn = FindFtnFrm();
1279         SwCntntFrm* pRefCnt = pFtn ? pFtn->GetRef() : 0;
1280         if ( pRefCnt && !pRefCnt->IsValid() )
1281         {
1282             SwFtnBossFrm* pFtnBossOfFtn = pFtn->FindFtnBossFrm();
1283             SwFtnBossFrm* pFtnBossOfRef = pRefCnt->FindFtnBossFrm();
1284             //<loop of movefwd until condition held or no move>
1285             if ( pFtnBossOfFtn && pFtnBossOfRef &&
1286                  pFtnBossOfFtn != pFtnBossOfRef &&
1287                  pFtnBossOfFtn->IsBefore( pFtnBossOfRef ) )
1288             {
1289                 bMovedFwd = sal_True;
1290                 MoveFwd( bMakePage, sal_False );
1291             }
1292         }
1293     }
1294 
1295     SWRECTFN( this )
1296 
1297     while ( !bValidPos || !bValidSize || !bValidPrtArea )
1298     {
1299         // --> OD 2006-09-25 #b6448963# - loop prevention
1300         SwRect aOldFrm_StopFormat( Frm() );
1301         SwRect aOldPrt_StopFormat( Prt() );
1302         // <--
1303         if ( sal_True == (bMoveable = IsMoveable()) )
1304         {
1305             SwFrm *pPre = GetIndPrev();
1306             if ( CheckMoveFwd( bMakePage, bKeep, bMovedBwd ) )
1307             {
1308                 SWREFRESHFN( this )
1309                 bMovedFwd = sal_True;
1310                 if ( bMovedBwd )
1311                 {
1312                     //Beim zurueckfliessen wurde der Upper angeregt sich
1313                     //vollstaendig zu Painten, dass koennen wir uns jetzt
1314                     //nach dem hin und her fliessen sparen.
1315                     GetUpper()->ResetCompletePaint();
1316                     //Der Vorgaenger wurde Invalidiert, das ist jetzt auch obsolete.
1317                     ASSERT( pPre, "missing old Prev" );
1318                     if( !pPre->IsSctFrm() )
1319                         ::ValidateSz( pPre );
1320                 }
1321                 bMoveable = IsMoveable();
1322             }
1323         }
1324 
1325         aOldFrmPos = (Frm().*fnRect->fnGetPos)();
1326         aOldPrtPos = (Prt().*fnRect->fnGetPos)();
1327 
1328         if ( !bValidPos )
1329             MakePos();
1330 
1331         //FixSize einstellen, die VarSize wird von Format() justiert.
1332         if ( !bValidSize )
1333         {
1334             // --> OD 2006-01-03 #125452#
1335             // invalidate printing area flag, if the following conditions are hold:
1336             // - current frame width is 0.
1337             // - current printing area width is 0.
1338             // - frame width is adjusted to a value greater than 0.
1339             // - printing area flag is sal_True.
1340             // Thus, it's assured that the printing area is adjusted, if the
1341             // frame area width changes its width from 0 to something greater
1342             // than 0.
1343             // Note: A text frame can be in such a situation, if the format is
1344             //       triggered by method call <SwCrsrShell::SetCrsr()> after
1345             //       loading the document.
1346             const SwTwips nNewFrmWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)();
1347             if ( bValidPrtArea && nNewFrmWidth > 0 &&
1348                  (Frm().*fnRect->fnGetWidth)() == 0 &&
1349                  (Prt().*fnRect->fnGetWidth)() == 0 )
1350             {
1351                 bValidPrtArea = sal_False;
1352             }
1353 
1354             (Frm().*fnRect->fnSetWidth)( nNewFrmWidth );
1355             // <--
1356         }
1357         if ( !bValidPrtArea )
1358         {
1359             const long nOldW = (Prt().*fnRect->fnGetWidth)();
1360             // --> OD 2004-09-28 #i34730# - keep current frame height
1361             const SwTwips nOldH = (Frm().*fnRect->fnGetHeight)();
1362             // <--
1363             MakePrtArea( rAttrs );
1364             if ( nOldW != (Prt().*fnRect->fnGetWidth)() )
1365                 Prepare( PREP_FIXSIZE_CHG );
1366             // --> OD 2004-09-28 #i34730# - check, if frame height has changed.
1367             // If yes, send a PREP_ADJUST_FRM and invalidate the size flag to
1368             // force a format. The format will check in its method
1369             // <SwTxtFrm::CalcPreps()>, if the already formatted lines still
1370             // fit and if not, performs necessary actions.
1371             // --> OD 2005-01-10 #i40150# - no check, if frame is undersized.
1372             if ( bValidSize && !IsUndersized() &&
1373                  nOldH != (Frm().*fnRect->fnGetHeight)() )
1374             {
1375                 // --> OD 2004-11-25 #115759# - no PREP_ADJUST_FRM and size
1376                 // invalidation, if height decreases only by the additional
1377                 // lower space as last content of a table cell and an existing
1378                 // follow containing one line exists.
1379                 const SwTwips nHDiff = nOldH - (Frm().*fnRect->fnGetHeight)();
1380                 const bool bNoPrepAdjustFrm =
1381                     nHDiff > 0 && IsInTab() && GetFollow() &&
1382                     ( 1 == static_cast<SwTxtFrm*>(GetFollow())->GetLineCount( STRING_LEN ) || (static_cast<SwTxtFrm*>(GetFollow())->Frm().*fnRect->fnGetWidth)() < 0 ) &&
1383                     GetFollow()->CalcAddLowerSpaceAsLastInTableCell() == nHDiff;
1384                 if ( !bNoPrepAdjustFrm )
1385                 {
1386                     Prepare( PREP_ADJUST_FRM );
1387                     bValidSize = sal_False;
1388                 }
1389                 // <--
1390             }
1391             // <--
1392         }
1393 
1394         //Damit die Witwen- und Waisen-Regelung eine Change bekommt muss der
1395         //CntntFrm benachrichtigt werden.
1396         //Kriterium:
1397         //- Er muss Moveable sein (sonst mach das Spalten keinen Sinn.)
1398         //- Er muss mit der Unterkante der PrtArea des Upper ueberlappen.
1399         if ( !bMustFit )
1400         {
1401             sal_Bool bWidow = sal_True;
1402             const SwTwips nDeadLine = (GetUpper()->*fnRect->fnGetPrtBottom)();
1403             if ( bMoveable && !bFormatted && ( GetFollow() ||
1404                  ( (Frm().*fnRect->fnOverStep)( nDeadLine ) ) ) )
1405             {
1406                 Prepare( PREP_WIDOWS_ORPHANS, 0, sal_False );
1407                 bValidSize = bWidow = sal_False;
1408             }
1409             if( (Frm().*fnRect->fnGetPos)() != aOldFrmPos ||
1410                 (Prt().*fnRect->fnGetPos)() != aOldPrtPos )
1411             {
1412                 // In diesem Prepare erfolgt ggf. ein _InvalidateSize().
1413                 // bValidSize wird sal_False und das Format() wird gerufen.
1414                 Prepare( PREP_POS_CHGD, (const void*)&bFormatted, sal_False );
1415                 if ( bWidow && GetFollow() )
1416                 {   Prepare( PREP_WIDOWS_ORPHANS, 0, sal_False );
1417                     bValidSize = sal_False;
1418                 }
1419             }
1420         }
1421         if ( !bValidSize )
1422         {
1423             bValidSize = bFormatted = sal_True;
1424             ++nFormatCount;
1425             if( nFormatCount > STOP_FLY_FORMAT )
1426                 SetFlyLock( sal_True );
1427             // --> OD 2006-09-25 #b6448963# - loop prevention
1428             // No format any longer, if <cnStopFormat> consequetive formats
1429             // without change occur.
1430             if ( nConsequetiveFormatsWithoutChange <= cnStopFormat )
1431             {
1432                 Format();
1433             }
1434 #if OSL_DEBUG_LEVEL > 1
1435             else
1436             {
1437                 ASSERT( false, "debug assertion: <SwCntntFrm::MakeAll()> - format of text frame suppressed by fix b6448963" );
1438             }
1439 #endif
1440             // <--
1441         }
1442 
1443         // FME 16.07.2003 #i16930# - removed this code because it did not work
1444 
1445         // OD 04.04.2003 #108446# - react on the situation detected in the text
1446         // formatting - see <SwTxtFrm::FormatAdjust(..)>:
1447         // text frame has to move forward, because its text formatting stopped,
1448         // created a follow and detected, that it contains no content.
1449 /*        if ( IsTxtFrm() && bValidPos && bValidSize && bValidPrtArea &&
1450              (Frm().*fnRect->fnGetHeight)() == 0 &&
1451              HasFollow()
1452            )
1453         {
1454             SwFrm* pOldUpper = GetUpper();
1455             MoveFwd( sal_True, sal_False );
1456             if ( GetUpper() != pOldUpper )
1457             {
1458                 bMovedFwd = sal_True;
1459                 SWREFRESHFN( this )
1460                 continue;
1461             }
1462         } */
1463 
1464         //Wenn ich der erste einer Kette bin koennte ich mal sehen ob
1465         //ich zurueckfliessen kann (wenn ich mich ueberhaupt bewegen soll).
1466         //Damit es keine Oszillation gibt, darf ich nicht gerade vorwaerts
1467         //geflossen sein.
1468         sal_Bool bDummy;
1469         if ( !lcl_Prev( this ) &&
1470              !bMovedFwd &&
1471              ( bMoveable || ( bFly && !bTab ) ) &&
1472              ( !bFtn || !GetUpper()->FindFtnFrm()->GetPrev() )
1473              && MoveBwd( bDummy ) )
1474         {
1475             SWREFRESHFN( this )
1476             bMovedBwd = sal_True;
1477             bFormatted = sal_False;
1478             if ( bKeep && bMoveable )
1479             {
1480                 if( CheckMoveFwd( bMakePage, sal_False, bMovedBwd ) )
1481                 {
1482                     bMovedFwd = sal_True;
1483                     bMoveable = IsMoveable();
1484                     SWREFRESHFN( this )
1485                 }
1486                 Point aOldPos = (Frm().*fnRect->fnGetPos)();
1487                 MakePos();
1488                 if( aOldPos != (Frm().*fnRect->fnGetPos)() )
1489                 {
1490                     Prepare( PREP_POS_CHGD, (const void*)&bFormatted, sal_False );
1491                     if ( !bValidSize )
1492                     {
1493                         (Frm().*fnRect->fnSetWidth)( (GetUpper()->
1494                                                 Prt().*fnRect->fnGetWidth)() );
1495                         if ( !bValidPrtArea )
1496                         {
1497                             const long nOldW = (Prt().*fnRect->fnGetWidth)();
1498                             MakePrtArea( rAttrs );
1499                             if( nOldW != (Prt().*fnRect->fnGetWidth)() )
1500                                 Prepare( PREP_FIXSIZE_CHG, 0, sal_False );
1501                         }
1502                         if( GetFollow() )
1503                             Prepare( PREP_WIDOWS_ORPHANS, 0, sal_False );
1504                         bValidSize = bFormatted = sal_True;
1505                         Format();
1506                     }
1507                 }
1508                 SwFrm *pNxt = HasFollow() ? NULL : FindNext();
1509                 while( pNxt && pNxt->IsSctFrm() )
1510                 {   // Leere Bereiche auslassen, in die anderen hinein
1511                     if( ((SwSectionFrm*)pNxt)->GetSection() )
1512                     {
1513                         SwFrm* pTmp = ((SwSectionFrm*)pNxt)->ContainsAny();
1514                         if( pTmp )
1515                         {
1516                             pNxt = pTmp;
1517                             break;
1518                         }
1519                     }
1520                     pNxt = pNxt->FindNext();
1521                 }
1522                 if ( pNxt )
1523                 {
1524                     pNxt->Calc();
1525                     if( bValidPos && !GetIndNext() )
1526                     {
1527                         SwSectionFrm *pSct = FindSctFrm();
1528                         if( pSct && !pSct->GetValidSizeFlag() )
1529                         {
1530                             SwSectionFrm* pNxtSct = pNxt->FindSctFrm();
1531                             if( pNxtSct && pSct->IsAnFollow( pNxtSct ) )
1532                                 bValidPos = sal_False;
1533                         }
1534                         else
1535                             bValidPos = sal_False;
1536                     }
1537                 }
1538             }
1539         }
1540 
1541         //Der TxtFrm Validiert sich bei Fussnoten ggf. selbst, dass kann leicht
1542         //dazu fuehren, dass seine Position obwohl unrichtig valide ist.
1543         if ( bValidPos )
1544         {
1545             // --> OD 2006-01-23 #i59341#
1546             // Workaround for inadequate layout algorithm:
1547             // suppress invalidation and calculation of position, if paragraph
1548             // has formatted itself at least STOP_FLY_FORMAT times and
1549             // has anchored objects.
1550             // Thus, the anchored objects get the possibility to format itself
1551             // and this probably solve the layout loop.
1552             if ( bFtn &&
1553                  nFormatCount <= STOP_FLY_FORMAT &&
1554                  !GetDrawObjs() )
1555             // <--
1556             {
1557                 bValidPos = sal_False;
1558                 MakePos();
1559                 aOldFrmPos = (Frm().*fnRect->fnGetPos)();
1560                 aOldPrtPos = (Prt().*fnRect->fnGetPos)();
1561             }
1562         }
1563 
1564         // --> OD 2006-09-25 #b6448963# - loop prevention
1565         {
1566             if ( aOldFrm_StopFormat == Frm() &&
1567                  aOldPrt_StopFormat == Prt() )
1568             {
1569                 ++nConsequetiveFormatsWithoutChange;
1570             }
1571             else
1572             {
1573                 nConsequetiveFormatsWithoutChange = 0;
1574             }
1575         }
1576         // <--
1577 
1578         //Wieder ein Wert ungueltig? - dann nochmal das ganze...
1579         if ( !bValidPos || !bValidSize || !bValidPrtArea )
1580             continue;
1581 
1582         //Fertig?
1583         // Achtung, wg. Hoehe==0, ist es besser statt Bottom() Top()+Height() zu nehmen
1584         // (kommt bei Undersized TxtFrms an der Unterkante eines spaltigen Bereichs vor)
1585         const long nPrtBottom = (GetUpper()->*fnRect->fnGetPrtBottom)();
1586         const long nBottomDist =  (Frm().*fnRect->fnBottomDist)( nPrtBottom );
1587         if( nBottomDist >= 0 )
1588         {
1589             if ( bKeep && bMoveable )
1590             {
1591                 //Wir sorgen dafuer, dass der Nachfolger gleich mit formatiert
1592                 //wird. Dadurch halten wir das Heft in der Hand, bis wirklich
1593                 //(fast) alles stabil ist. So vermeiden wir Endlosschleifen,
1594                 //die durch staendig wiederholte Versuche entstehen.
1595                 //Das bMoveFwdInvalid ist fuer #38407# notwendig. War urspruenglich
1596                 //in flowfrm.cxx rev 1.38 behoben, das unterbrach aber obiges
1597                 //Schema und spielte lieber Tuerme von Hanoi (#43669#).
1598                 SwFrm *pNxt = HasFollow() ? NULL : FindNext();
1599                 // Bei Bereichen nehmen wir lieber den Inhalt, denn nur
1600                 // dieser kann ggf. die Seite wechseln
1601                 while( pNxt && pNxt->IsSctFrm() )
1602                 {
1603                     if( ((SwSectionFrm*)pNxt)->GetSection() )
1604                     {
1605                         pNxt = ((SwSectionFrm*)pNxt)->ContainsAny();
1606                         break;
1607                     }
1608                     pNxt = pNxt->FindNext();
1609                 }
1610                 if ( pNxt )
1611                 {
1612                     const sal_Bool bMoveFwdInvalid = 0 != GetIndNext();
1613                     const sal_Bool bNxtNew =
1614                         ( 0 == (pNxt->Prt().*fnRect->fnGetHeight)() ) &&
1615                         (!pNxt->IsTxtFrm() ||!((SwTxtFrm*)pNxt)->IsHiddenNow());
1616 
1617                     pNxt->Calc();
1618 
1619                     if ( !bMovedBwd &&
1620                          ((bMoveFwdInvalid && !GetIndNext()) ||
1621                           bNxtNew) )
1622                     {
1623                         if( bMovedFwd )
1624                             pNotify->SetInvaKeep();
1625                         bMovedFwd = sal_False;
1626                     }
1627                 }
1628             }
1629             continue;
1630         }
1631 
1632         //Ich passe nicht mehr in meinen Uebergeordneten, also ist es jetzt
1633         //an der Zeit moeglichst konstruktive Veranderungen vorzunehmen
1634 
1635         //Wenn ich den uebergeordneten Frm nicht verlassen darf, habe
1636         //ich ein Problem; Frei nach Artur Dent tun wir das einzige das man
1637         //mit einen nicht loesbaren Problem tun kann: wir ignorieren es - und
1638         //zwar mit aller Kraft.
1639         if ( !bMoveable || IsUndersized() )
1640         {
1641             if( !bMoveable && IsInTab() )
1642             {
1643                 long nDiff = -(Frm().*fnRect->fnBottomDist)(
1644                                         (GetUpper()->*fnRect->fnGetPrtBottom)() );
1645                 long nReal = GetUpper()->Grow( nDiff );
1646                 if( nReal )
1647                     continue;
1648             }
1649             break;
1650         }
1651 
1652         //Wenn ich nun ueberhaupt ganz und garnicht in meinen Upper passe
1653         //so kann die Situation vielleicht doch noch durch Aufbrechen
1654         //aufgeklart werden. Diese Situation tritt bei einem frisch
1655         //erzeugten Follow auf, der zwar auf die Folgeseite geschoben wurde
1656         //aber selbst noch zu gross fuer diese ist; also wiederum
1657         //aufgespalten werden muss.
1658         //Wenn ich nicht passe und nicht Spaltbar (WouldFit()) bin, so schicke
1659         //ich meinem TxtFrmanteil die Nachricht, dass eben falls moeglich
1660         //trotz des Attributes 'nicht aufspalten' aufgespalten werden muss.
1661         sal_Bool bMoveOrFit = sal_False;
1662         sal_Bool bDontMoveMe = !GetIndPrev();
1663         if( bDontMoveMe && IsInSct() )
1664         {
1665             SwFtnBossFrm* pBoss = FindFtnBossFrm();
1666             bDontMoveMe = !pBoss->IsInSct() ||
1667                           ( !pBoss->Lower()->GetNext() && !pBoss->GetPrev() );
1668         }
1669 
1670         // Finally, we are able to split table rows. Therefore, bDontMoveMe
1671         // can be set to sal_False:
1672         if( bDontMoveMe && IsInTab() &&
1673             0 != const_cast<SwCntntFrm*>(this)->GetNextCellLeaf( MAKEPAGE_NONE ) )
1674             bDontMoveMe = sal_False;
1675 
1676         if ( bDontMoveMe && (Frm().*fnRect->fnGetHeight)() >
1677                             (GetUpper()->Prt().*fnRect->fnGetHeight)() )
1678         {
1679             if ( !bFitPromise )
1680             {
1681                 SwTwips nTmp = (GetUpper()->Prt().*fnRect->fnGetHeight)() -
1682                                (Prt().*fnRect->fnGetTop)();
1683                 sal_Bool bSplit = !IsFwdMoveAllowed();
1684                 if ( nTmp > 0 && WouldFit( nTmp, bSplit, sal_False ) )
1685                 {
1686                     Prepare( PREP_WIDOWS_ORPHANS, 0, sal_False );
1687                     bValidSize = sal_False;
1688                     bFitPromise = sal_True;
1689                     continue;
1690                 }
1691                 /* -----------------19.02.99 12:58-------------------
1692                  * Frueher wurde in Rahmen und Bereichen niemals versucht,
1693                  * durch bMoveOrFit den TxtFrm unter Verzicht auf seine
1694                  * Attribute (Widows,Keep) doch noch passend zu bekommen.
1695                  * Dies haette zumindest bei spaltigen Rahmen versucht
1696                  * werden muessen, spaetestens bei verketteten Rahmen und
1697                  * in Bereichen muss es versucht werden.
1698                  * Ausnahme: Wenn wir im FormatWidthCols stehen, duerfen die
1699                  * Attribute nicht ausser Acht gelassen werden.
1700                  * --------------------------------------------------*/
1701                 else if ( !bFtn && bMoveable &&
1702                       ( !bFly || !FindFlyFrm()->IsColLocked() ) &&
1703                       ( !bSct || !FindSctFrm()->IsColLocked() ) )
1704                     bMoveOrFit = sal_True;
1705             }
1706 #ifdef DBG_UTIL
1707             else
1708             {
1709                 ASSERT( sal_False, "+TxtFrm hat WouldFit-Versprechen nicht eingehalten." );
1710             }
1711 #endif
1712         }
1713 
1714         //Mal sehen ob ich irgenwo Platz finde...
1715         //Benachbarte Fussnoten werden in _MoveFtnCntFwd 'vorgeschoben'
1716         SwFrm *pPre = GetIndPrev();
1717         SwFrm *pOldUp = GetUpper();
1718 
1719 /* MA 13. Oct. 98: Was soll das denn sein!?
1720  * AMA 14. Dec 98: Wenn ein spaltiger Bereich keinen Platz mehr fuer seinen ersten ContentFrm
1721  *      bietet, so soll dieser nicht nur in die naechste Spalte, sondern ggf. bis zur naechsten
1722  *      Seite wandern und dort einen Section-Follow erzeugen.
1723  */
1724         if( IsInSct() && bMovedFwd && bMakePage && pOldUp->IsColBodyFrm() &&
1725             pOldUp->GetUpper()->GetUpper()->IsSctFrm() &&
1726             ( pPre || pOldUp->GetUpper()->GetPrev() ) &&
1727             ((SwSectionFrm*)pOldUp->GetUpper()->GetUpper())->MoveAllowed(this) )
1728             bMovedFwd = sal_False;
1729 
1730         const sal_Bool bCheckForGrownBody = pOldUp->IsBodyFrm();
1731         const long nOldBodyHeight = (pOldUp->Frm().*fnRect->fnGetHeight)();
1732 
1733         if ( !bMovedFwd && !MoveFwd( bMakePage, sal_False ) )
1734             bMakePage = sal_False;
1735         SWREFRESHFN( this )
1736 
1737         // If MoveFwd moves the paragraph to the next page, a following
1738         // paragraph, which contains footnotes can can cause the old upper
1739         // frame to grow. In this case we explicitely allow a new check
1740         // for MoveBwd. Robust: We also check the bMovedBwd flag again.
1741         // If pOldUp was a footnote frame, it has been deleted inside MoveFwd.
1742         // Therefore we only check for growing body frames.
1743         if ( bCheckForGrownBody && ! bMovedBwd && pOldUp != GetUpper() &&
1744              (pOldUp->Frm().*fnRect->fnGetHeight)() > nOldBodyHeight )
1745             bMovedFwd = sal_False;
1746         else
1747             bMovedFwd = sal_True;
1748 
1749         bFormatted = sal_False;
1750         if ( bMoveOrFit && GetUpper() == pOldUp )
1751         {
1752             // FME 2007-08-30 #i81146# new loop control
1753             if ( nConsequetiveFormatsWithoutChange <= cnStopFormat )
1754             {
1755                 Prepare( PREP_MUST_FIT, 0, sal_False );
1756                 bValidSize = sal_False;
1757                 bMustFit = sal_True;
1758                 continue;
1759             }
1760 
1761 #if OSL_DEBUG_LEVEL > 1
1762             ASSERT( false, "LoopControl in SwCntntFrm::MakeAll" )
1763 #endif
1764         }
1765         if ( bMovedBwd && GetUpper() )
1766         {   //Unuetz gewordene Invalidierungen zuruecknehmen.
1767             GetUpper()->ResetCompletePaint();
1768             if( pPre && !pPre->IsSctFrm() )
1769                 ::ValidateSz( pPre );
1770         }
1771 
1772     } //while ( !bValidPos || !bValidSize || !bValidPrtArea )
1773 
1774 
1775     // NEW: Looping Louie (Light). Should not be applied in balanced sections.
1776     // Should only be applied if there is no better solution!
1777     LOOPING_LOUIE_LIGHT( bMovedFwd && bMovedBwd && !IsInBalancedSection() &&
1778                             (
1779 
1780                                 // --> FME 2005-01-26 #118572#
1781                                 ( bFtn && !FindFtnFrm()->GetRef()->IsInSct() ) ||
1782                                 // <--
1783 
1784                                 // --> FME 2005-01-27 #i33887#
1785                                 ( IsInSct() && bKeep )
1786                                 // <--
1787 
1788                                 // ... add your conditions here ...
1789 
1790                             ),
1791                          static_cast<SwTxtFrm&>(*this) );
1792 
1793 
1794     if ( pSaveFtn )
1795         delete pSaveFtn;
1796 
1797     UnlockJoin();
1798     if ( bMovedFwd || bMovedBwd )
1799         pNotify->SetInvaKeep();
1800     // OD 2004-02-26 #i25029#
1801     if ( bMovedFwd )
1802     {
1803         pNotify->SetInvalidatePrevPrtArea();
1804     }
1805     delete pNotify;
1806     SetFlyLock( sal_False );
1807 }
1808 
1809 /*************************************************************************
1810 |*
1811 |*  SwCntntFrm::_WouldFit()
1812 |*
1813 |*  Ersterstellung      MA 28. Feb. 95
1814 |*  Letzte Aenderung    AMA 15. Feb. 99
1815 |*
1816 |*************************************************************************/
1817 
1818 
1819 
1820 
1821 void MakeNxt( SwFrm *pFrm, SwFrm *pNxt )
1822 {
1823     //fix(25455): Validieren, sonst kommt es zu einer Rekursion.
1824     //Der erste Versuch, der Abbruch mit pFrm = 0 wenn !Valid,
1825     //fuehrt leider zu dem Problem, dass das Keep dann u.U. nicht mehr
1826     //korrekt beachtet wird (27417)
1827     const sal_Bool bOldPos = pFrm->GetValidPosFlag();
1828     const sal_Bool bOldSz  = pFrm->GetValidSizeFlag();
1829     const sal_Bool bOldPrt = pFrm->GetValidPrtAreaFlag();
1830     pFrm->bValidPos = pFrm->bValidPrtArea = pFrm->bValidSize = sal_True;
1831 
1832     //fix(29272): Nicht MakeAll rufen, dort wird evtl. pFrm wieder invalidert
1833     //und kommt rekursiv wieder herein.
1834     if ( pNxt->IsCntntFrm() )
1835     {
1836         SwCntntNotify aNotify( (SwCntntFrm*)pNxt );
1837         SwBorderAttrAccess aAccess( SwFrm::GetCache(), pNxt );
1838         const SwBorderAttrs &rAttrs = *aAccess.Get();
1839         if ( !pNxt->GetValidSizeFlag() )
1840         {
1841             if( pNxt->IsVertical() )
1842                 pNxt->Frm().Height( pNxt->GetUpper()->Prt().Height() );
1843             else
1844                 pNxt->Frm().Width( pNxt->GetUpper()->Prt().Width() );
1845         }
1846         ((SwCntntFrm*)pNxt)->MakePrtArea( rAttrs );
1847         pNxt->Format( &rAttrs );
1848     }
1849     else
1850     {
1851         SwLayNotify aNotify( (SwLayoutFrm*)pNxt );
1852         SwBorderAttrAccess aAccess( SwFrm::GetCache(), pNxt );
1853         const SwBorderAttrs &rAttrs = *aAccess.Get();
1854         if ( !pNxt->GetValidSizeFlag() )
1855         {
1856             if( pNxt->IsVertical() )
1857                 pNxt->Frm().Height( pNxt->GetUpper()->Prt().Height() );
1858             else
1859                 pNxt->Frm().Width( pNxt->GetUpper()->Prt().Width() );
1860         }
1861         pNxt->Format( &rAttrs );
1862     }
1863 
1864     pFrm->bValidPos      = bOldPos;
1865     pFrm->bValidSize     = bOldSz;
1866     pFrm->bValidPrtArea  = bOldPrt;
1867 }
1868 
1869 // Diese Routine ueberprueft, ob zwischen dem FtnBoss von pFrm und dem
1870 // von pNxt keine anderen FtnBosse liegen
1871 
1872 sal_Bool lcl_IsNextFtnBoss( const SwFrm *pFrm, const SwFrm* pNxt )
1873 {
1874     ASSERT( pFrm && pNxt, "lcl_IsNextFtnBoss: No Frames?" );
1875     pFrm = pFrm->FindFtnBossFrm();
1876     pNxt = pNxt->FindFtnBossFrm();
1877     // Falls pFrm eine letzte Spalte ist, wird stattdessen die Seite genommen
1878     while( pFrm && pFrm->IsColumnFrm() && !pFrm->GetNext() )
1879         pFrm = pFrm->GetUpper()->FindFtnBossFrm();
1880     // Falls pNxt eine erste Spalte ist, wird stattdessen die Seite genommen
1881     while( pNxt && pNxt->IsColumnFrm() && !pNxt->GetPrev() )
1882         pNxt = pNxt->GetUpper()->FindFtnBossFrm();
1883     // So, jetzt muessen pFrm und pNxt entweder zwei benachbarte Seiten oder Spalten sein.
1884     return ( pFrm && pNxt && pFrm->GetNext() == pNxt );
1885 }
1886 
1887 // --> OD 2007-11-26 #b6614158#
1888 sal_Bool SwCntntFrm::_WouldFit( SwTwips nSpace,
1889                             SwLayoutFrm *pNewUpper,
1890                             sal_Bool bTstMove,
1891                             const bool bObjsInNewUpper )
1892 // <--
1893 {
1894     //Damit die Fussnote sich ihren Platz sorgsam waehlt, muss
1895     //sie in jedem Fall gemoved werden, wenn zwischen dem
1896     //neuen Upper und ihrer aktuellen Seite/Spalte mindestens eine
1897     //Seite/Spalte liegt.
1898     SwFtnFrm* pFtnFrm = 0;
1899     if ( IsInFtn() )
1900     {
1901         if( !lcl_IsNextFtnBoss( pNewUpper, this ) )
1902             return sal_True;
1903         pFtnFrm = FindFtnFrm();
1904     }
1905 
1906     sal_Bool bRet;
1907     sal_Bool bSplit = !pNewUpper->Lower();
1908     SwCntntFrm *pFrm = this;
1909     const SwFrm *pTmpPrev = pNewUpper->Lower();
1910     if( pTmpPrev && pTmpPrev->IsFtnFrm() )
1911         pTmpPrev = ((SwFtnFrm*)pTmpPrev)->Lower();
1912     while ( pTmpPrev && pTmpPrev->GetNext() )
1913         pTmpPrev = pTmpPrev->GetNext();
1914     do
1915     {
1916         // --> FME 2005-03-31 #b6236853# #i46181#
1917         SwTwips nSecondCheck = 0;
1918         SwTwips nOldSpace = nSpace;
1919         sal_Bool bOldSplit = bSplit;
1920         // <--
1921 
1922         if ( bTstMove || IsInFly() || ( IsInSct() &&
1923              ( pFrm->GetUpper()->IsColBodyFrm() || ( pFtnFrm &&
1924                pFtnFrm->GetUpper()->GetUpper()->IsColumnFrm() ) ) ) )
1925         {
1926             //Jetzt wirds ein bischen hinterlistig; empfindliche Gemueter sollten
1927             //lieber wegsehen. Wenn ein Flys Spalten enthaelt so sind die Cntnts
1928             //moveable, mit Ausnahme der in der letzten Spalte (siehe
1929             //SwFrm::IsMoveable()). Zurueckfliessen duerfen sie aber natuerlich.
1930             //Das WouldFit() liefert leider nur dann einen vernueftigen Wert, wenn
1931             //der Frm moveable ist. Um dem WouldFit() einen Moveable Frm
1932             //vorzugaukeln haenge ich ihn einfach solange um.
1933             // Auch bei spaltigen Bereichen muss umgehaengt werden, damit
1934             // SwSectionFrm::Growable() den richtigen Wert liefert.
1935             // Innerhalb von Fussnoten muss ggf. sogar der SwFtnFrm umgehaengt werden,
1936             // falls es dort keinen SwFtnFrm gibt.
1937             SwFrm* pTmpFrm = pFrm->IsInFtn() && !pNewUpper->FindFtnFrm() ?
1938                              (SwFrm*)pFrm->FindFtnFrm() : pFrm;
1939             SwLayoutFrm *pUp = pTmpFrm->GetUpper();
1940             SwFrm *pOldNext = pTmpFrm->GetNext();
1941             pTmpFrm->Remove();
1942             pTmpFrm->InsertBefore( pNewUpper, 0 );
1943             if ( pFrm->IsTxtFrm() &&
1944                  ( bTstMove ||
1945                    ((SwTxtFrm*)pFrm)->HasFollow() ||
1946                    ( !((SwTxtFrm*)pFrm)->HasPara() &&
1947                      !((SwTxtFrm*)pFrm)->IsEmpty()
1948                    )
1949                  )
1950                )
1951             {
1952                 bTstMove = sal_True;
1953                 bRet = ((SwTxtFrm*)pFrm)->TestFormat( pTmpPrev, nSpace, bSplit );
1954             }
1955             else
1956                 bRet = pFrm->WouldFit( nSpace, bSplit, sal_False );
1957 
1958             pTmpFrm->Remove();
1959             pTmpFrm->InsertBefore( pUp, pOldNext );
1960         }
1961         else
1962         {
1963             bRet = pFrm->WouldFit( nSpace, bSplit, sal_False );
1964             nSecondCheck = !bSplit ? 1 : 0;
1965         }
1966 
1967         SwBorderAttrAccess aAccess( SwFrm::GetCache(), pFrm );
1968         const SwBorderAttrs &rAttrs = *aAccess.Get();
1969 
1970         //Bitter aber wahr: Der Abstand muss auch noch mit einkalkuliert werden.
1971         //Bei TestFormatierung ist dies bereits geschehen.
1972         if ( bRet && !bTstMove )
1973         {
1974             SwTwips nUpper;
1975 
1976             if ( pTmpPrev )
1977             {
1978                 nUpper = CalcUpperSpace( NULL, pTmpPrev );
1979 
1980                 // in balanced columned section frames we do not want the
1981                 // common border
1982                 sal_Bool bCommonBorder = sal_True;
1983                 if ( pFrm->IsInSct() && pFrm->GetUpper()->IsColBodyFrm() )
1984                 {
1985                     const SwSectionFrm* pSct = pFrm->FindSctFrm();
1986                     bCommonBorder = pSct->GetFmt()->GetBalancedColumns().GetValue();
1987                 }
1988 
1989                 // --> FME 2005-03-31 #b6236853# #i46181#
1990                 nSecondCheck = ( 1 == nSecondCheck &&
1991                                  pFrm == this &&
1992                                  IsTxtFrm() &&
1993                                  bCommonBorder &&
1994                                  !static_cast<const SwTxtFrm*>(this)->IsEmpty() ) ?
1995                                  nUpper :
1996                                  0;
1997                 // <--
1998 
1999                 nUpper += bCommonBorder ?
2000                           rAttrs.GetBottomLine( *(pFrm) ) :
2001                           rAttrs.CalcBottomLine();
2002 
2003             }
2004             else
2005             {
2006                 // --> FME 2005-03-31 #b6236853# #i46181#
2007                 nSecondCheck = 0;
2008                 // <--
2009 
2010                 if( pFrm->IsVertical() )
2011                     nUpper = pFrm->Frm().Width() - pFrm->Prt().Width();
2012                 else
2013                     nUpper = pFrm->Frm().Height() - pFrm->Prt().Height();
2014             }
2015 
2016             nSpace -= nUpper;
2017 
2018             if ( nSpace < 0 )
2019             {
2020                 bRet = sal_False;
2021 
2022                 // --> FME 2005-03-31 #b6236853# #i46181#
2023                 if ( nSecondCheck > 0 )
2024                 {
2025                     // The following code is indented to solve a (rare) problem
2026                     // causing some frames not to move backward:
2027                     // SwTxtFrm::WouldFit() claims that the whole paragraph
2028                     // fits into the given space and subtracts the height of
2029                     // all lines from nSpace. nSpace - nUpper is not a valid
2030                     // indicator if the frame should be allowed to move backward.
2031                     // We do a second check with the original remaining space
2032                     // reduced by the required upper space:
2033                     nOldSpace -= nSecondCheck;
2034                     const bool bSecondRet = nOldSpace >= 0 && pFrm->WouldFit( nOldSpace, bOldSplit, sal_False );
2035                     if ( bSecondRet && bOldSplit && nOldSpace >= 0 )
2036                     {
2037                         bRet = sal_True;
2038                         bSplit = sal_True;
2039                     }
2040                 }
2041                 // <--
2042             }
2043         }
2044 
2045         // OD 2004-03-01 #106629# - also consider lower spacing in table cells
2046         if ( bRet && IsInTab() &&
2047              pNewUpper->GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS) )
2048         {
2049             nSpace -= rAttrs.GetULSpace().GetLower();
2050             if ( nSpace < 0 )
2051             {
2052                 bRet = sal_False;
2053             }
2054         }
2055 
2056         if ( bRet && !bSplit && pFrm->IsKeep( rAttrs.GetAttrSet() ) )
2057         {
2058             if( bTstMove )
2059             {
2060                 while( pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->HasFollow() )
2061                 {
2062                     pFrm = ((SwTxtFrm*)pFrm)->GetFollow();
2063                 }
2064                 // OD 11.04.2003 #108824# - If last follow frame of <this> text
2065                 // frame isn't valid, a formatting of the next content frame
2066                 // doesn't makes sense. Thus, return sal_True.
2067                 if ( IsAnFollow( pFrm ) && !pFrm->IsValid() )
2068                 {
2069                     ASSERT( false, "Only a warning for task 108824:/n<SwCntntFrm::_WouldFit(..) - follow not valid!" );
2070                     return sal_True;
2071                 }
2072             }
2073             SwFrm *pNxt;
2074             if( 0 != (pNxt = pFrm->FindNext()) && pNxt->IsCntntFrm() &&
2075                 ( !pFtnFrm || ( pNxt->IsInFtn() &&
2076                   pNxt->FindFtnFrm()->GetAttr() == pFtnFrm->GetAttr() ) ) )
2077             {
2078                 // ProbeFormatierung vertraegt keine absatz- oder gar zeichengebundene Objekte
2079                 // --> OD 2007-11-26 #b6614158#
2080                 // current solution for the test formatting doesn't work, if
2081                 // objects are present in the remaining area of the new upper
2082                 if ( bTstMove &&
2083                      ( pNxt->GetDrawObjs() || bObjsInNewUpper ) )
2084                 {
2085                     return sal_True;
2086                 }
2087                 // <--
2088 
2089                 if ( !pNxt->IsValid() )
2090                     MakeNxt( pFrm, pNxt );
2091 
2092                 //Kleiner Trick: Wenn der naechste einen Vorgaenger hat, so hat
2093                 //er den Absatzabstand bereits berechnet. Er braucht dann nicht
2094                 //teuer kalkuliert werden.
2095                 if( lcl_NotHiddenPrev( pNxt ) )
2096                     pTmpPrev = 0;
2097                 else
2098                 {
2099                     if( pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->IsHiddenNow() )
2100                         pTmpPrev = lcl_NotHiddenPrev( pFrm );
2101                     else
2102                         pTmpPrev = pFrm;
2103                 }
2104                 pFrm = (SwCntntFrm*)pNxt;
2105             }
2106             else
2107                 pFrm = 0;
2108         }
2109         else
2110             pFrm = 0;
2111 
2112     } while ( bRet && pFrm );
2113 
2114     return bRet;
2115 }
2116