Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "rootfrm.hxx"
21 : #include "pagefrm.hxx"
22 : #include "viewopt.hxx"
23 : #include "frmtool.hxx"
24 : #include "txtftn.hxx"
25 : #include "fmtftn.hxx"
26 : #include <editeng/ulspitem.hxx>
27 : #include <editeng/keepitem.hxx>
28 : #include <svx/sdtaitm.hxx>
29 :
30 : #include <fmtfsize.hxx>
31 : #include <fmtanchr.hxx>
32 : #include <fmtclbl.hxx>
33 :
34 : #include "tabfrm.hxx"
35 : #include "ftnfrm.hxx"
36 : #include "txtfrm.hxx"
37 : #include "sectfrm.hxx"
38 : #include "dbg_lay.hxx"
39 :
40 : // #i28701#
41 : #include <sortedobjs.hxx>
42 : #include <layouter.hxx>
43 : // #i36347#
44 : #include <flyfrms.hxx>
45 :
46 : // Move methods
47 :
48 : /// Return value tells whether the Frm should be moved.
49 0 : bool SwCntntFrm::ShouldBwdMoved( SwLayoutFrm *pNewUpper, bool, bool & )
50 : {
51 0 : if ( (SwFlowFrm::IsMoveBwdJump() || !IsPrevObjMove()))
52 : {
53 : // Floating back a frm uses a bit of time unfortunately.
54 : // The most common case is the following: The Frm wants to float to
55 : // somewhere where the FixSize is the same that the Frm itself has already.
56 : // In that case it's pretty easy to check if the Frm has enough space
57 : // for its VarSize. If this is NOT the case, we already know that
58 : // we don't need to move.
59 : // The Frm checks itself whether it has enough space - respecting the fact
60 : // that it could possibly split itself if needed.
61 : // If, however, the FixSize differs from the Frm or Flys are involved
62 : // (either in the old or the new position), checking is pointless,
63 : // and we have to move the Frm just to see what happens - if there's
64 : // some space available to do it, that is.
65 :
66 : // The FixSize of the containers of Cntnts is always the width.
67 :
68 : // If we moved more than one sheet back (for example jumping over empty
69 : // pages), we have to move either way. Otherwise, if the Frm doesn't fit
70 : // into the page, empty pages wouldn't be respected anymore.
71 0 : sal_uInt8 nMoveAnyway = 0;
72 0 : SwPageFrm * const pNewPage = pNewUpper->FindPageFrm();
73 0 : SwPageFrm *pOldPage = FindPageFrm();
74 :
75 0 : if ( SwFlowFrm::IsMoveBwdJump() )
76 0 : return true;
77 :
78 0 : if( IsInFtn() && IsInSct() )
79 : {
80 0 : SwFtnFrm* pFtn = FindFtnFrm();
81 0 : SwSectionFrm* pMySect = pFtn->FindSctFrm();
82 0 : if( pMySect && pMySect->IsFtnLock() )
83 : {
84 0 : SwSectionFrm *pSect = pNewUpper->FindSctFrm();
85 0 : while( pSect && pSect->IsInFtn() )
86 0 : pSect = pSect->GetUpper()->FindSctFrm();
87 : OSL_ENSURE( pSect, "Escaping footnote" );
88 0 : if( pSect != pMySect )
89 0 : return false;
90 : }
91 : }
92 0 : SWRECTFN( this )
93 0 : SWRECTFNX( pNewUpper )
94 0 : if( std::abs( (pNewUpper->Prt().*fnRectX->fnGetWidth)() -
95 0 : (GetUpper()->Prt().*fnRect->fnGetWidth)() ) > 1 ) {
96 : // In this case, only a _WouldFit with test move is possible
97 0 : nMoveAnyway = 2;
98 : }
99 :
100 : // OD 2004-05-26 #i25904# - do *not* move backward,
101 : // if <nMoveAnyway> equals 3 and no space is left in new upper.
102 0 : nMoveAnyway |= BwdMoveNecessary( pOldPage, Frm() );
103 : {
104 0 : const IDocumentSettingAccess* pIDSA = pNewPage->GetFmt()->getIDocumentSettingAccess();
105 0 : SwTwips nSpace = 0;
106 0 : SwRect aRect( pNewUpper->Prt() );
107 0 : aRect.Pos() += pNewUpper->Frm().Pos();
108 0 : const SwFrm *pPrevFrm = pNewUpper->Lower();
109 0 : while ( pPrevFrm )
110 : {
111 0 : SwTwips nNewTop = (pPrevFrm->Frm().*fnRectX->fnGetBottom)();
112 : // OD 2004-03-01 #106629#:
113 : // consider lower spacing of last frame in a table cell
114 : {
115 : // check, if last frame is inside table and if it includes
116 : // its lower spacing.
117 0 : if ( !pPrevFrm->GetNext() && pPrevFrm->IsInTab() &&
118 0 : pIDSA->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS) )
119 : {
120 0 : const SwFrm* pLastFrm = pPrevFrm;
121 : // if last frame is a section, take its last content
122 0 : if ( pPrevFrm->IsSctFrm() )
123 : {
124 0 : pLastFrm = static_cast<const SwSectionFrm*>(pPrevFrm)->FindLastCntnt();
125 0 : if ( pLastFrm &&
126 0 : pLastFrm->FindTabFrm() != pPrevFrm->FindTabFrm() )
127 : {
128 0 : pLastFrm = pLastFrm->FindTabFrm();
129 : }
130 : }
131 :
132 0 : if ( pLastFrm )
133 : {
134 0 : SwBorderAttrAccess aAccess( SwFrm::GetCache(), pLastFrm );
135 0 : const SwBorderAttrs& rAttrs = *aAccess.Get();
136 0 : nNewTop -= rAttrs.GetULSpace().GetLower();
137 : }
138 : }
139 : }
140 0 : (aRect.*fnRectX->fnSetTop)( nNewTop );
141 :
142 0 : pPrevFrm = pPrevFrm->GetNext();
143 : }
144 :
145 0 : nMoveAnyway |= BwdMoveNecessary( pNewPage, aRect);
146 :
147 : //determine space left in new upper frame
148 0 : nSpace = (aRect.*fnRectX->fnGetHeight)();
149 0 : const SwViewShell *pSh = pNewUpper->getRootFrm()->GetCurrShell();
150 0 : if ( IsInFtn() ||
151 0 : (pSh && pSh->GetViewOptions()->getBrowseMode()) ||
152 0 : pNewUpper->IsCellFrm() ||
153 0 : ( pNewUpper->IsInSct() && ( pNewUpper->IsSctFrm() ||
154 0 : ( pNewUpper->IsColBodyFrm() &&
155 0 : !pNewUpper->GetUpper()->GetPrev() &&
156 0 : !pNewUpper->GetUpper()->GetNext() ) ) ) )
157 0 : nSpace += pNewUpper->Grow( LONG_MAX, sal_True );
158 :
159 0 : if ( nMoveAnyway < 3 )
160 : {
161 0 : if ( nSpace )
162 : {
163 : // Do not notify footnotes which are stuck to the paragraph:
164 : // This would require extremely confusing code, taking into
165 : // account the widths
166 : // and Flys, that in turn influence the footnotes, ...
167 :
168 : // _WouldFit can only be used if the width is the same and
169 : // ONLY self-anchored Flys are present.
170 :
171 : // _WouldFit can also be used if ONLY Flys anchored
172 : // somewhere else are present.
173 : // In this case, the width doesn't even matter,
174 : // because we're running a TestFormat in the new upper.
175 : const sal_uInt8 nBwdMoveNecessaryResult =
176 0 : BwdMoveNecessary( pNewPage, aRect);
177 0 : const bool bObjsInNewUpper( nBwdMoveNecessaryResult == 2 ||
178 0 : nBwdMoveNecessaryResult == 3 );
179 :
180 : return _WouldFit( nSpace, pNewUpper, nMoveAnyway == 2,
181 0 : bObjsInNewUpper );
182 : }
183 : // It's impossible for _WouldFit to return a usable result if
184 : // we have a fresh multi-column section - so we really have to
185 : // float back unless there is no space.
186 0 : return pNewUpper->IsInSct() && pNewUpper->IsColBodyFrm() &&
187 0 : !(pNewUpper->Prt().*fnRectX->fnGetWidth)() &&
188 0 : ( pNewUpper->GetUpper()->GetPrev() ||
189 0 : pNewUpper->GetUpper()->GetNext() );
190 : }
191 :
192 : // OD 2004-05-26 #i25904# - check for space left in new upper
193 0 : return nSpace != 0;
194 : }
195 : }
196 0 : return false;
197 : }
198 :
199 : // Calc methods
200 :
201 : // Two little friendships form a secret society
202 0 : inline void PrepareLock( SwFlowFrm *pTab )
203 : {
204 0 : pTab->LockJoin();
205 0 : }
206 0 : inline void PrepareUnlock( SwFlowFrm *pTab )
207 : {
208 0 : pTab->UnlockJoin();
209 :
210 0 : }
211 :
212 : // hopefully, one day this function simply will return 'false'
213 0 : static bool lcl_IsCalcUpperAllowed( const SwFrm& rFrm )
214 : {
215 0 : return !rFrm.GetUpper()->IsSctFrm() &&
216 0 : !rFrm.GetUpper()->IsFooterFrm() &&
217 : // #i23129#, #i36347# - no format of upper Writer fly frame
218 0 : !rFrm.GetUpper()->IsFlyFrm() &&
219 0 : !( rFrm.GetUpper()->IsTabFrm() && rFrm.GetUpper()->GetUpper()->IsInTab() ) &&
220 0 : !( rFrm.IsTabFrm() && rFrm.GetUpper()->IsInTab() );
221 : }
222 :
223 : /** Prepares the Frame for "formatting" (MakeAll()).
224 : *
225 : * This method serves to save stack space: To calculate the position of the Frm
226 : * we have to make sure that the positions of Upper and Prev respectively are
227 : * valid. This may require a recursive call (a loop would be quite expensive,
228 : * as it's not required very often).
229 : *
230 : * Every call of MakeAll requires around 500 bytes on the stack - you easily
231 : * see where this leads to. This method requires only a little bit of stack
232 : * space, so the recursive call should not be a problem here.
233 : *
234 : * Another advantage is that one nice day, this method and with it the
235 : * formatting of predecessors could be avoided. Then it could probably be
236 : * possible to jump "quickly" to the document's end.
237 : *
238 : * @see MakeAll()
239 : */
240 0 : void SwFrm::PrepareMake()
241 : {
242 0 : StackHack aHack;
243 0 : if ( GetUpper() )
244 : {
245 0 : if ( lcl_IsCalcUpperAllowed( *this ) )
246 0 : GetUpper()->Calc();
247 : OSL_ENSURE( GetUpper(), ":-( Layout unstable (Upper gone)." );
248 0 : if ( !GetUpper() )
249 0 : return;
250 :
251 0 : const bool bCnt = IsCntntFrm();
252 0 : const bool bTab = IsTabFrm();
253 0 : sal_Bool bNoSect = IsInSct();
254 0 : sal_Bool bOldTabLock = sal_False, bFoll = sal_False;
255 0 : SwFlowFrm* pThis = bCnt ? (SwCntntFrm*)this : NULL;
256 :
257 0 : if ( bTab )
258 : {
259 0 : pThis = (SwTabFrm*)this;
260 0 : bOldTabLock = ((SwTabFrm*)this)->IsJoinLocked();
261 0 : ::PrepareLock( (SwTabFrm*)this );
262 0 : bFoll = pThis->IsFollow();
263 : }
264 0 : else if( IsSctFrm() )
265 : {
266 0 : pThis = (SwSectionFrm*)this;
267 0 : bFoll = pThis->IsFollow();
268 0 : bNoSect = sal_False;
269 : }
270 0 : else if ( bCnt && sal_True == (bFoll = pThis->IsFollow()) &&
271 0 : GetPrev() )
272 : {
273 : //Do not follow the chain when we need only one instance
274 0 : const SwTxtFrm* pMaster = ((SwCntntFrm*)this)->FindMaster();
275 0 : if ( pMaster && pMaster->IsLocked() )
276 : {
277 0 : MakeAll();
278 0 : return;
279 : }
280 : }
281 :
282 : // #i44049# - no format of previous frame, if current
283 : // frame is a table frame and its previous frame wants to keep with it.
284 0 : const bool bFormatPrev = !bTab ||
285 0 : !GetPrev() ||
286 0 : !GetPrev()->GetAttrSet()->GetKeep().GetValue();
287 0 : if ( bFormatPrev )
288 : {
289 0 : SwFrm *pFrm = GetUpper()->Lower();
290 0 : while ( pFrm != this )
291 : {
292 : OSL_ENSURE( pFrm, ":-( Layout unstable (this not found)." );
293 0 : if ( !pFrm )
294 0 : return; //Oioioioi ...
295 :
296 0 : if ( !pFrm->IsValid() )
297 : {
298 : // A small interference that hopefully improves on the stability:
299 : // If I'm Follow AND neighbor of a Frm before me, it would delete
300 : // me when formatting. This as you can see could easily become a
301 : // confusing situation that we want to avoid.
302 0 : if ( bFoll && pFrm->IsFlowFrm() &&
303 0 : (SwFlowFrm::CastFlowFrm(pFrm))->IsAnFollow( pThis ) )
304 0 : break;
305 :
306 0 : pFrm->MakeAll();
307 0 : if( IsSctFrm() && !((SwSectionFrm*)this)->GetSection() )
308 0 : break;
309 : }
310 : // With CntntFrms, the chain may be broken while walking through
311 : // it. Therefore we have to figure out the follower in a bit more
312 : // complicated way. However, I'll HAVE to get back to myself
313 : // sometime again.
314 0 : pFrm = pFrm->FindNext();
315 :
316 : // If we started out in a SectionFrm, it might have happened that
317 : // we landed in a Section Follow via the MakeAll calls.
318 : // FindNext only gives us the SectionFrm, not it's content - we
319 : // won't find ourselves anymore!
320 0 : if( bNoSect && pFrm && pFrm->IsSctFrm() )
321 : {
322 0 : SwFrm* pCnt = ((SwSectionFrm*)pFrm)->ContainsAny();
323 0 : if( pCnt )
324 0 : pFrm = pCnt;
325 : }
326 : }
327 : OSL_ENSURE( GetUpper(), "Layout unstable (Upper gone II)." );
328 0 : if ( !GetUpper() )
329 0 : return;
330 :
331 0 : if ( lcl_IsCalcUpperAllowed( *this ) )
332 0 : GetUpper()->Calc();
333 :
334 : OSL_ENSURE( GetUpper(), "Layout unstable (Upper gone III)." );
335 : }
336 :
337 0 : if ( bTab && !bOldTabLock )
338 0 : ::PrepareUnlock( (SwTabFrm*)this );
339 : }
340 0 : MakeAll();
341 : }
342 :
343 0 : void SwFrm::OptPrepareMake()
344 : {
345 : // #i23129#, #i36347# - no format of upper Writer fly frame
346 0 : if ( GetUpper() && !GetUpper()->IsFooterFrm() &&
347 0 : !GetUpper()->IsFlyFrm() )
348 : {
349 0 : GetUpper()->Calc();
350 : OSL_ENSURE( GetUpper(), ":-( Layout unstable (Upper gone)." );
351 0 : if ( !GetUpper() )
352 0 : return;
353 : }
354 0 : if ( GetPrev() && !GetPrev()->IsValid() )
355 0 : PrepareMake();
356 : else
357 : {
358 0 : StackHack aHack;
359 0 : MakeAll();
360 : }
361 : }
362 :
363 0 : void SwFrm::PrepareCrsr()
364 : {
365 0 : StackHack aHack;
366 0 : if( GetUpper() && !GetUpper()->IsSctFrm() )
367 : {
368 0 : GetUpper()->PrepareCrsr();
369 0 : GetUpper()->Calc();
370 :
371 : OSL_ENSURE( GetUpper(), ":-( Layout unstable (Upper gone)." );
372 0 : if ( !GetUpper() )
373 0 : return;
374 :
375 0 : const bool bCnt = IsCntntFrm();
376 0 : const bool bTab = IsTabFrm();
377 0 : sal_Bool bNoSect = IsInSct();
378 :
379 0 : sal_Bool bOldTabLock = sal_False, bFoll;
380 0 : SwFlowFrm* pThis = bCnt ? (SwCntntFrm*)this : NULL;
381 :
382 0 : if ( bTab )
383 : {
384 0 : bOldTabLock = ((SwTabFrm*)this)->IsJoinLocked();
385 0 : ::PrepareLock( (SwTabFrm*)this );
386 0 : pThis = (SwTabFrm*)this;
387 : }
388 0 : else if( IsSctFrm() )
389 : {
390 0 : pThis = (SwSectionFrm*)this;
391 0 : bNoSect = sal_False;
392 : }
393 0 : bFoll = pThis && pThis->IsFollow();
394 :
395 0 : SwFrm *pFrm = GetUpper()->Lower();
396 0 : while ( pFrm != this )
397 : {
398 : OSL_ENSURE( pFrm, ":-( Layout unstable (this not found)." );
399 0 : if ( !pFrm )
400 0 : return; //Oioioioi ...
401 :
402 0 : if ( !pFrm->IsValid() )
403 : {
404 : // A small interference that hopefully improves on the stability:
405 : // If I'm Follow AND neighbor of a Frm before me, it would delete
406 : // me when formatting. This as you can see could easily become a
407 : // confusing situation that we want to avoid.
408 0 : if ( bFoll && pFrm->IsFlowFrm() &&
409 0 : (SwFlowFrm::CastFlowFrm(pFrm))->IsAnFollow( pThis ) )
410 0 : break;
411 :
412 0 : pFrm->MakeAll();
413 : }
414 : // With CntntFrms, the chain may be broken while walking through
415 : // it. Therefore we have to figure out the follower in a bit more
416 : // complicated way. However, I'll HAVE to get back to myself
417 : // sometime again.
418 0 : pFrm = pFrm->FindNext();
419 0 : if( bNoSect && pFrm && pFrm->IsSctFrm() )
420 : {
421 0 : SwFrm* pCnt = ((SwSectionFrm*)pFrm)->ContainsAny();
422 0 : if( pCnt )
423 0 : pFrm = pCnt;
424 : }
425 : }
426 : OSL_ENSURE( GetUpper(), "Layout unstable (Upper gone II)." );
427 0 : if ( !GetUpper() )
428 0 : return;
429 :
430 0 : GetUpper()->Calc();
431 :
432 : OSL_ENSURE( GetUpper(), "Layout unstable (Upper gone III)." );
433 :
434 0 : if ( bTab && !bOldTabLock )
435 0 : ::PrepareUnlock( (SwTabFrm*)this );
436 : }
437 0 : Calc();
438 : }
439 :
440 : // Here we return GetPrev(); however we will ignore empty SectionFrms
441 0 : static SwFrm* lcl_Prev( SwFrm* pFrm, bool bSectPrv = true )
442 : {
443 0 : SwFrm* pRet = pFrm->GetPrev();
444 0 : if( !pRet && pFrm->GetUpper() && pFrm->GetUpper()->IsSctFrm() &&
445 0 : bSectPrv && !pFrm->IsColumnFrm() )
446 0 : pRet = pFrm->GetUpper()->GetPrev();
447 0 : while( pRet && pRet->IsSctFrm() &&
448 0 : !((SwSectionFrm*)pRet)->GetSection() )
449 0 : pRet = pRet->GetPrev();
450 0 : return pRet;
451 : }
452 :
453 0 : static SwFrm* lcl_NotHiddenPrev( SwFrm* pFrm )
454 : {
455 0 : SwFrm *pRet = pFrm;
456 0 : do
457 : {
458 0 : pRet = lcl_Prev( pRet );
459 0 : } while ( pRet && pRet->IsTxtFrm() && ((SwTxtFrm*)pRet)->IsHiddenNow() );
460 0 : return pRet;
461 : }
462 :
463 0 : void SwFrm::MakePos()
464 : {
465 0 : if ( !mbValidPos )
466 : {
467 0 : mbValidPos = sal_True;
468 0 : bool bUseUpper = false;
469 0 : SwFrm* pPrv = lcl_Prev( this );
470 0 : if ( pPrv &&
471 0 : ( !pPrv->IsCntntFrm() ||
472 0 : ( ((SwCntntFrm*)pPrv)->GetFollow() != this ) )
473 : )
474 : {
475 0 : if ( !StackHack::IsLocked() &&
476 0 : ( !IsInSct() || IsSctFrm() ) &&
477 0 : !pPrv->IsSctFrm() &&
478 0 : !pPrv->GetAttrSet()->GetKeep().GetValue()
479 : )
480 : {
481 0 : pPrv->Calc(); // This may cause Prev to vanish!
482 : }
483 0 : else if ( pPrv->Frm().Top() == 0 )
484 : {
485 0 : bUseUpper = true;
486 : }
487 : }
488 :
489 0 : pPrv = lcl_Prev( this, false );
490 0 : sal_uInt16 nMyType = GetType();
491 0 : SWRECTFN( ( IsCellFrm() && GetUpper() ? GetUpper() : this ) )
492 0 : if ( !bUseUpper && pPrv )
493 : {
494 0 : maFrm.Pos( pPrv->Frm().Pos() );
495 0 : if( FRM_NEIGHBOUR & nMyType )
496 : {
497 0 : sal_Bool bR2L = IsRightToLeft();
498 0 : if( bR2L )
499 0 : (maFrm.*fnRect->fnSetPosX)( (maFrm.*fnRect->fnGetLeft)() -
500 0 : (maFrm.*fnRect->fnGetWidth)() );
501 : else
502 0 : (maFrm.*fnRect->fnSetPosX)( (maFrm.*fnRect->fnGetLeft)() +
503 0 : (pPrv->Frm().*fnRect->fnGetWidth)() );
504 :
505 : // cells may now leave their uppers
506 0 : if( bVert && FRM_CELL & nMyType && !mbReverse )
507 0 : maFrm.Pos().setX(maFrm.Pos().getX() - maFrm.Width() + pPrv->Frm().Width());
508 : }
509 0 : else if( bVert && FRM_NOTE_VERT & nMyType )
510 : {
511 0 : if( mbReverse )
512 0 : maFrm.Pos().setX(maFrm.Pos().getX() + pPrv->Frm().Width());
513 : else
514 : //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
515 : {
516 0 : if ( bVertL2R )
517 0 : maFrm.Pos().setX(maFrm.Pos().getX() + pPrv->Frm().Width());
518 : else
519 0 : maFrm.Pos().setX(maFrm.Pos().getX() - maFrm.Width());
520 : }
521 : }
522 : else
523 0 : maFrm.Pos().setY(maFrm.Pos().getY() + pPrv->Frm().Height());
524 : }
525 0 : else if ( GetUpper() )
526 : {
527 : // OD 15.10.2002 #103517# - add safeguard for <SwFooterFrm::Calc()>
528 : // If parent frame is a footer frame and its <ColLocked()>, then
529 : // do *not* calculate it.
530 : // NOTE: Footer frame is <ColLocked()> during its
531 : // <FormatSize(..)>, which is called from <Format(..)>, which
532 : // is called from <MakeAll()>, which is called from <Calc()>.
533 : // #i56850#
534 : // - no format of upper Writer fly frame, which is anchored
535 : // at-paragraph or at-character.
536 0 : if ( !GetUpper()->IsTabFrm() &&
537 0 : !( IsTabFrm() && GetUpper()->IsInTab() ) &&
538 0 : !GetUpper()->IsSctFrm() &&
539 0 : !dynamic_cast<SwFlyAtCntFrm*>(GetUpper()) &&
540 0 : !( GetUpper()->IsFooterFrm() &&
541 0 : GetUpper()->IsColLocked() )
542 : )
543 : {
544 0 : GetUpper()->Calc();
545 : }
546 0 : pPrv = lcl_Prev( this, false );
547 0 : if ( !bUseUpper && pPrv )
548 : {
549 0 : maFrm.Pos( pPrv->Frm().Pos() );
550 0 : if( FRM_NEIGHBOUR & nMyType )
551 : {
552 0 : sal_Bool bR2L = IsRightToLeft();
553 0 : if( bR2L )
554 0 : (maFrm.*fnRect->fnSetPosX)( (maFrm.*fnRect->fnGetLeft)() -
555 0 : (maFrm.*fnRect->fnGetWidth)() );
556 : else
557 0 : (maFrm.*fnRect->fnSetPosX)( (maFrm.*fnRect->fnGetLeft)() +
558 0 : (pPrv->Frm().*fnRect->fnGetWidth)() );
559 :
560 : // cells may now leave their uppers
561 0 : if( bVert && FRM_CELL & nMyType && !mbReverse )
562 0 : maFrm.Pos().setX(maFrm.Pos().getX() - maFrm.Width() + pPrv->Frm().Width());
563 : }
564 0 : else if( bVert && FRM_NOTE_VERT & nMyType )
565 : {
566 0 : if( mbReverse )
567 0 : maFrm.Pos().setX(maFrm.Pos().getX() + pPrv->Frm().Width());
568 : else
569 0 : maFrm.Pos().setX(maFrm.Pos().getX() - maFrm.Width());
570 : }
571 : else
572 0 : maFrm.Pos().setY(maFrm.Pos().getY() + pPrv->Frm().Height());
573 : }
574 : else
575 : {
576 0 : maFrm.Pos( GetUpper()->Frm().Pos() );
577 0 : if( GetUpper()->IsFlyFrm() )
578 0 : maFrm.Pos() += static_cast<SwFlyFrm*>(GetUpper())->ContentPos();
579 : else
580 0 : maFrm.Pos() += GetUpper()->Prt().Pos();
581 :
582 0 : if( FRM_NEIGHBOUR & nMyType && IsRightToLeft() )
583 : {
584 0 : if( bVert )
585 0 : maFrm.Pos().setY(maFrm.Pos().getY() + GetUpper()->Prt().Height()
586 0 : - maFrm.Height());
587 : else
588 0 : maFrm.Pos().setX(maFrm.Pos().getX() + GetUpper()->Prt().Width()
589 0 : - maFrm.Width());
590 : }
591 : //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
592 0 : else if( bVert && !bVertL2R && FRM_NOTE_VERT & nMyType && !mbReverse )
593 0 : maFrm.Pos().setX(maFrm.Pos().getX() - maFrm.Width() + GetUpper()->Prt().Width());
594 : }
595 : }
596 : else
597 : {
598 0 : maFrm.Pos().setX(0);
599 0 : maFrm.Pos().setY(0);
600 : }
601 : //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
602 0 : if( IsBodyFrm() && bVert && !bVertL2R && !mbReverse && GetUpper() )
603 0 : maFrm.Pos().setX(maFrm.Pos().getX() + GetUpper()->Prt().Width() - maFrm.Width());
604 0 : mbValidPos = sal_True;
605 : }
606 0 : }
607 :
608 : // #i28701# - new type <SwSortedObjs>
609 0 : static void lcl_CheckObjects( SwSortedObjs* pSortedObjs, SwFrm* pFrm, long& rBot )
610 : {
611 : // And then there can be paragraph anchored frames that sit below their paragraph.
612 0 : long nMax = 0;
613 0 : for ( sal_uInt16 i = 0; i < pSortedObjs->Count(); ++i )
614 : {
615 : // #i28701# - consider changed type of <SwSortedObjs>
616 : // entries.
617 0 : SwAnchoredObject* pObj = (*pSortedObjs)[i];
618 0 : long nTmp = 0;
619 0 : if ( pObj->ISA(SwFlyFrm) )
620 : {
621 0 : SwFlyFrm *pFly = static_cast<SwFlyFrm*>(pObj);
622 0 : if( pFly->Frm().Top() != FAR_AWAY &&
623 0 : ( pFrm->IsPageFrm() ? pFly->IsFlyLayFrm() :
624 0 : ( pFly->IsFlyAtCntFrm() &&
625 0 : ( pFrm->IsBodyFrm() ? pFly->GetAnchorFrm()->IsInDocBody() :
626 0 : pFly->GetAnchorFrm()->IsInFtn() ) ) ) )
627 : {
628 0 : nTmp = pFly->Frm().Bottom();
629 : }
630 : }
631 : else
632 0 : nTmp = pObj->GetObjRect().Bottom();
633 0 : nMax = std::max( nTmp, nMax );
634 : }
635 0 : ++nMax; // Lower edge vs. height!
636 0 : rBot = std::max( rBot, nMax );
637 0 : }
638 :
639 0 : void SwPageFrm::MakeAll()
640 : {
641 : PROTOCOL_ENTER( this, PROT_MAKEALL, 0, 0 )
642 :
643 0 : const SwRect aOldRect( Frm() ); // Adjust root size
644 0 : const SwLayNotify aNotify( this ); // takes care of the notification in the dtor
645 0 : SwBorderAttrAccess *pAccess = 0;
646 0 : const SwBorderAttrs*pAttrs = 0;
647 :
648 0 : while ( !mbValidPos || !mbValidSize || !mbValidPrtArea )
649 : {
650 0 : if ( !mbValidPos )
651 : {
652 0 : mbValidPos = sal_True; // positioning of the pages is taken care of by the root frame
653 : }
654 :
655 0 : if ( !mbValidSize || !mbValidPrtArea )
656 : {
657 0 : if ( IsEmptyPage() )
658 : {
659 0 : Frm().Width( 0 ); Prt().Width( 0 );
660 0 : Frm().Height( 0 ); Prt().Height( 0 );
661 0 : Prt().Left( 0 ); Prt().Top( 0 );
662 0 : mbValidSize = mbValidPrtArea = sal_True;
663 : }
664 : else
665 : {
666 0 : if ( !pAccess )
667 : {
668 0 : pAccess = new SwBorderAttrAccess( SwFrm::GetCache(), this );
669 0 : pAttrs = pAccess->Get();
670 : }
671 : // In BrowseView, we use fixed settings
672 0 : SwViewShell *pSh = getRootFrm()->GetCurrShell();
673 0 : if ( pSh && pSh->GetViewOptions()->getBrowseMode() )
674 : {
675 0 : const Size aBorder = pSh->GetOut()->PixelToLogic( pSh->GetBrowseBorder() );
676 0 : const long nTop = pAttrs->CalcTopLine() + aBorder.Height();
677 0 : const long nBottom = pAttrs->CalcBottomLine()+ aBorder.Height();
678 :
679 0 : long nWidth = GetUpper() ? ((SwRootFrm*)GetUpper())->GetBrowseWidth() : 0;
680 0 : if ( nWidth < pSh->GetBrowseWidth() )
681 0 : nWidth = pSh->GetBrowseWidth();
682 0 : nWidth += + 2 * aBorder.Width();
683 :
684 0 : nWidth = std::max( nWidth, 2L * aBorder.Width() + 4L*MM50 );
685 0 : Frm().Width( nWidth );
686 :
687 0 : SwLayoutFrm *pBody = FindBodyCont();
688 0 : if ( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrm() )
689 : {
690 : // Columns have a fixed height
691 0 : Frm().Height( pAttrs->GetSize().Height() );
692 : }
693 : else
694 : {
695 : // In pages without columns, the content defines the size.
696 0 : long nBot = Frm().Top() + nTop;
697 0 : SwFrm *pFrm = Lower();
698 0 : while ( pFrm )
699 : {
700 0 : long nTmp = 0;
701 0 : SwFrm *pCnt = ((SwLayoutFrm*)pFrm)->ContainsAny();
702 0 : while ( pCnt && (pCnt->GetUpper() == pFrm ||
703 0 : ((SwLayoutFrm*)pFrm)->IsAnLower( pCnt )))
704 : {
705 0 : nTmp += pCnt->Frm().Height();
706 0 : if( pCnt->IsTxtFrm() &&
707 0 : ((SwTxtFrm*)pCnt)->IsUndersized() )
708 0 : nTmp += ((SwTxtFrm*)pCnt)->GetParHeight()
709 0 : - pCnt->Prt().Height();
710 0 : else if( pCnt->IsSctFrm() &&
711 0 : ((SwSectionFrm*)pCnt)->IsUndersized() )
712 0 : nTmp += ((SwSectionFrm*)pCnt)->Undersize();
713 0 : pCnt = pCnt->FindNext();
714 : }
715 : // OD 29.10.2002 #97265# - consider invalid body frame properties
716 0 : if ( pFrm->IsBodyFrm() &&
717 0 : ( !pFrm->GetValidSizeFlag() ||
718 0 : !pFrm->GetValidPrtAreaFlag() ) &&
719 0 : ( pFrm->Frm().Height() < pFrm->Prt().Height() )
720 : )
721 : {
722 0 : nTmp = std::min( nTmp, pFrm->Frm().Height() );
723 : }
724 : else
725 : {
726 : // OD 30.10.2002 #97265# - assert invalid lower property
727 : OSL_ENSURE( !(pFrm->Frm().Height() < pFrm->Prt().Height()),
728 : "SwPageFrm::MakeAll(): Lower with frame height < printing height" );
729 0 : nTmp += pFrm->Frm().Height() - pFrm->Prt().Height();
730 : }
731 0 : if ( !pFrm->IsBodyFrm() )
732 0 : nTmp = std::min( nTmp, pFrm->Frm().Height() );
733 0 : nBot += nTmp;
734 : // Here we check whether paragraph anchored objects
735 : // protrude outside the Body/FtnCont.
736 0 : if( pSortedObjs && !pFrm->IsHeaderFrm() &&
737 0 : !pFrm->IsFooterFrm() )
738 0 : lcl_CheckObjects( pSortedObjs, pFrm, nBot );
739 0 : pFrm = pFrm->GetNext();
740 : }
741 0 : nBot += nBottom;
742 : // And the page anchored ones
743 0 : if ( pSortedObjs )
744 0 : lcl_CheckObjects( pSortedObjs, this, nBot );
745 0 : nBot -= Frm().Top();
746 : // #i35143# - If second page frame
747 : // exists, the first page doesn't have to fulfill the
748 : // visible area.
749 0 : if ( !GetPrev() && !GetNext() )
750 : {
751 0 : nBot = std::max( nBot, pSh->VisArea().Height() );
752 : }
753 : // #i35143# - Assure, that the page
754 : // doesn't exceed the defined browse height.
755 0 : Frm().Height( std::min( nBot, BROWSE_HEIGHT ) );
756 : }
757 0 : Prt().Left ( pAttrs->CalcLeftLine() + aBorder.Width() );
758 0 : Prt().Top ( nTop );
759 0 : Prt().Width( Frm().Width() - ( Prt().Left()
760 0 : + pAttrs->CalcRightLine() + aBorder.Width() ) );
761 0 : Prt().Height( Frm().Height() - (nTop + nBottom) );
762 0 : mbValidSize = mbValidPrtArea = sal_True;
763 : }
764 : else
765 : { // Set FixSize. For pages, this is not done from Upper, but from
766 : // the attribute.
767 0 : Frm().SSize( pAttrs->GetSize() );
768 0 : Format( pAttrs );
769 : }
770 : }
771 : }
772 : } //while ( !mbValidPos || !mbValidSize || !mbValidPrtArea )
773 0 : delete pAccess;
774 :
775 0 : if ( Frm() != aOldRect && GetUpper() )
776 0 : static_cast<SwRootFrm*>(GetUpper())->CheckViewLayout( 0, 0 );
777 :
778 : OSL_ENSURE( !GetUpper() || GetUpper()->Prt().Width() >= maFrm.Width(),
779 0 : "Upper (Root) must be wide enough to contain the widest page");
780 0 : }
781 :
782 0 : void SwLayoutFrm::MakeAll()
783 : {
784 : PROTOCOL_ENTER( this, PROT_MAKEALL, 0, 0 )
785 :
786 : // takes care of the notification in the dtor
787 0 : const SwLayNotify aNotify( this );
788 0 : bool bVert = IsVertical();
789 : //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
790 0 : SwRectFn fnRect = ( IsNeighbourFrm() == bVert )? fnRectHori : ( IsVertLR() ? fnRectVertL2R : fnRectVert );
791 :
792 0 : SwBorderAttrAccess *pAccess = 0;
793 0 : const SwBorderAttrs*pAttrs = 0;
794 :
795 0 : while ( !mbValidPos || !mbValidSize || !mbValidPrtArea )
796 : {
797 0 : if ( !mbValidPos )
798 0 : MakePos();
799 :
800 0 : if ( GetUpper() )
801 : {
802 : // NEW TABLES
803 0 : if ( IsLeaveUpperAllowed() )
804 : {
805 0 : if ( !mbValidSize )
806 0 : mbValidPrtArea = sal_False;
807 : }
808 : else
809 : {
810 0 : if ( !mbValidSize )
811 : {
812 : // Set FixSize; VarSize is set by Format() after calculating the PrtArea
813 0 : mbValidPrtArea = sal_False;
814 :
815 0 : SwTwips nPrtWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)();
816 0 : if( bVert && ( IsBodyFrm() || IsFtnContFrm() ) )
817 : {
818 0 : SwFrm* pNxt = GetPrev();
819 0 : while( pNxt && !pNxt->IsHeaderFrm() )
820 0 : pNxt = pNxt->GetPrev();
821 0 : if( pNxt )
822 0 : nPrtWidth -= pNxt->Frm().Height();
823 0 : pNxt = GetNext();
824 0 : while( pNxt && !pNxt->IsFooterFrm() )
825 0 : pNxt = pNxt->GetNext();
826 0 : if( pNxt )
827 0 : nPrtWidth -= pNxt->Frm().Height();
828 : }
829 :
830 0 : const long nDiff = nPrtWidth - (Frm().*fnRect->fnGetWidth)();
831 :
832 0 : if( IsNeighbourFrm() && IsRightToLeft() )
833 0 : (Frm().*fnRect->fnSubLeft)( nDiff );
834 : else
835 0 : (Frm().*fnRect->fnAddRight)( nDiff );
836 : }
837 : else
838 : {
839 : // Don't leave your upper
840 0 : const SwTwips nDeadLine = (GetUpper()->*fnRect->fnGetPrtBottom)();
841 0 : if( (Frm().*fnRect->fnOverStep)( nDeadLine ) )
842 0 : mbValidSize = sal_False;
843 : }
844 : }
845 : }
846 0 : if ( !mbValidSize || !mbValidPrtArea )
847 : {
848 0 : if ( !pAccess )
849 : {
850 0 : pAccess = new SwBorderAttrAccess( SwFrm::GetCache(), this );
851 0 : pAttrs = pAccess->Get();
852 : }
853 0 : Format( pAttrs );
854 : }
855 : } //while ( !mbValidPos || !mbValidSize || !mbValidPrtArea )
856 0 : delete pAccess;
857 0 : }
858 :
859 0 : bool SwTxtNode::IsCollapse() const
860 : {
861 0 : if (GetDoc()->get( IDocumentSettingAccess::COLLAPSE_EMPTY_CELL_PARA )
862 0 : && GetTxt().isEmpty())
863 : {
864 0 : sal_uLong nIdx=GetIndex();
865 0 : const SwEndNode *pNdBefore=GetNodes()[nIdx-1]->GetEndNode();
866 0 : const SwEndNode *pNdAfter=GetNodes()[nIdx+1]->GetEndNode();
867 :
868 : // The paragraph is collapsed only if the NdAfter is the end of a cell
869 0 : bool bInTable = this->FindTableNode( ) != NULL;
870 :
871 0 : SwSortedObjs* pObjs = this->getLayoutFrm( GetDoc()->GetCurrentLayout() )->GetDrawObjs( );
872 0 : sal_uInt32 nObjs = ( pObjs != NULL ) ? pObjs->Count( ) : 0;
873 :
874 0 : return pNdBefore!=NULL && pNdAfter!=NULL && nObjs == 0 && bInTable;
875 : }
876 :
877 0 : return false;
878 : }
879 :
880 0 : bool SwFrm::IsCollapse() const
881 : {
882 0 : if (!IsTxtFrm())
883 0 : return false;
884 :
885 0 : const SwTxtFrm *pTxtFrm=(SwTxtFrm*)this;
886 0 : const SwTxtNode *pTxtNode=pTxtFrm->GetTxtNode();
887 0 : return pTxtNode && pTxtNode->IsCollapse();
888 : }
889 :
890 0 : sal_Bool SwCntntFrm::MakePrtArea( const SwBorderAttrs &rAttrs )
891 : {
892 0 : sal_Bool bSizeChgd = sal_False;
893 :
894 0 : if ( !mbValidPrtArea )
895 : {
896 0 : mbValidPrtArea = sal_True;
897 :
898 0 : SWRECTFN( this )
899 0 : const bool bTxtFrm = IsTxtFrm();
900 0 : SwTwips nUpper = 0;
901 0 : if ( bTxtFrm && ((SwTxtFrm*)this)->IsHiddenNow() )
902 : {
903 0 : if ( ((SwTxtFrm*)this)->HasFollow() )
904 0 : ((SwTxtFrm*)this)->JoinFrm();
905 :
906 0 : if( (Prt().*fnRect->fnGetHeight)() )
907 0 : ((SwTxtFrm*)this)->HideHidden();
908 0 : Prt().Pos().setX(0);
909 0 : Prt().Pos().setY(0);
910 0 : (Prt().*fnRect->fnSetWidth)( (Frm().*fnRect->fnGetWidth)() );
911 0 : (Prt().*fnRect->fnSetHeight)( 0 );
912 0 : nUpper = -( (Frm().*fnRect->fnGetHeight)() );
913 : }
914 : else
915 : {
916 : // Simplification: CntntFrms are always variable in height!
917 :
918 : // At the FixSize, the surrounding Frame enforces the size;
919 : // the borders are simply subtracted.
920 0 : const long nLeft = rAttrs.CalcLeft( this );
921 0 : const long nRight = ((SwBorderAttrs&)rAttrs).CalcRight( this );
922 0 : (this->*fnRect->fnSetXMargins)( nLeft, nRight );
923 :
924 0 : SwViewShell *pSh = getRootFrm()->GetCurrShell();
925 : SwTwips nWidthArea;
926 0 : if( pSh && 0!=(nWidthArea=(pSh->VisArea().*fnRect->fnGetWidth)()) &&
927 0 : GetUpper()->IsPageBodyFrm() && // but not for BodyFrms in Columns
928 0 : pSh->GetViewOptions()->getBrowseMode() )
929 : {
930 : // Do not protrude the edge of the visible area. The page may be
931 : // wider, because there may be objects with excess width
932 : // (RootFrm::ImplCalcBrowseWidth())
933 0 : long nMinWidth = 0;
934 :
935 0 : for (sal_uInt16 i = 0; GetDrawObjs() && i < GetDrawObjs()->Count();++i)
936 : {
937 : // #i28701# - consider changed type of
938 : // <SwSortedObjs> entries
939 0 : SwAnchoredObject* pObj = (*GetDrawObjs())[i];
940 0 : const SwFrmFmt& rFmt = pObj->GetFrmFmt();
941 0 : const sal_Bool bFly = pObj->ISA(SwFlyFrm);
942 0 : if ((bFly && (FAR_AWAY == pObj->GetObjRect().Width()))
943 0 : || rFmt.GetFrmSize().GetWidthPercent())
944 : {
945 0 : continue;
946 : }
947 :
948 0 : if ( FLY_AS_CHAR == rFmt.GetAnchor().GetAnchorId() )
949 : {
950 : nMinWidth = std::max( nMinWidth,
951 0 : bFly ? rFmt.GetFrmSize().GetWidth()
952 0 : : pObj->GetObjRect().Width() );
953 : }
954 : }
955 :
956 0 : const Size aBorder = pSh->GetOut()->PixelToLogic( pSh->GetBrowseBorder() );
957 0 : long nWidth = nWidthArea - 2 * ( IsVertical() ? aBorder.Height() : aBorder.Width() );
958 0 : nWidth -= (Prt().*fnRect->fnGetLeft)();
959 0 : nWidth -= rAttrs.CalcRightLine();
960 0 : nWidth = std::max( nMinWidth, nWidth );
961 0 : (Prt().*fnRect->fnSetWidth)( std::min( nWidth,
962 0 : (Prt().*fnRect->fnGetWidth)() ) );
963 : }
964 :
965 0 : if ( (Prt().*fnRect->fnGetWidth)() <= MINLAY )
966 : {
967 : // The PrtArea should already be at least MINLAY wide, matching the
968 : // minimal values of the UI
969 0 : (Prt().*fnRect->fnSetWidth)( std::min( long(MINLAY),
970 0 : (Frm().*fnRect->fnGetWidth)() ) );
971 0 : SwTwips nTmp = (Frm().*fnRect->fnGetWidth)() -
972 0 : (Prt().*fnRect->fnGetWidth)();
973 0 : if( (Prt().*fnRect->fnGetLeft)() > nTmp )
974 0 : (Prt().*fnRect->fnSetLeft)( nTmp );
975 : }
976 :
977 : // The following rules apply for VarSize:
978 : // 1. The first entry of a chain has no top border
979 : // 2. There is never a bottom border
980 : // 3. The top border is the maximum of the distance
981 : // of Prev downwards and our own distance upwards
982 : // Those three rules apply when calculating spacings
983 : // that are given by UL- and LRSpace. There might be a spacing
984 : // in all directions however; this may be caused by borders
985 : // and / or shadows.
986 : // 4. The spacing for TextFrms corresponds to the interline lead,
987 : // at a minimum.
988 :
989 0 : nUpper = CalcUpperSpace( &rAttrs, NULL );
990 :
991 0 : SwTwips nLower = CalcLowerSpace( &rAttrs );
992 0 : if (IsCollapse()) {
993 0 : nUpper=0;
994 0 : nLower=0;
995 : }
996 :
997 0 : (Prt().*fnRect->fnSetPosY)( (!bVert || mbReverse) ? nUpper : nLower);
998 0 : nUpper += nLower;
999 0 : nUpper -= (Frm().*fnRect->fnGetHeight)() -
1000 0 : (Prt().*fnRect->fnGetHeight)();
1001 : }
1002 : // If there's a difference between old and new size, call Grow() or
1003 : // Shrink() respectively.
1004 0 : if ( nUpper )
1005 : {
1006 0 : if ( nUpper > 0 )
1007 0 : GrowFrm( nUpper );
1008 : else
1009 0 : ShrinkFrm( -nUpper );
1010 0 : bSizeChgd = sal_True;
1011 : }
1012 : }
1013 0 : return bSizeChgd;
1014 : }
1015 :
1016 : #define STOP_FLY_FORMAT 10
1017 : // - loop prevention
1018 : const int cnStopFormat = 15;
1019 :
1020 0 : inline void ValidateSz( SwFrm *pFrm )
1021 : {
1022 0 : if ( pFrm )
1023 : {
1024 0 : pFrm->mbValidSize = sal_True;
1025 0 : pFrm->mbValidPrtArea = sal_True;
1026 : }
1027 0 : }
1028 :
1029 0 : void SwCntntFrm::MakeAll()
1030 : {
1031 : OSL_ENSURE( GetUpper(), "no Upper?" );
1032 : OSL_ENSURE( IsTxtFrm(), "MakeAll(), NoTxt" );
1033 :
1034 0 : if ( !IsFollow() && StackHack::IsLocked() )
1035 0 : return;
1036 :
1037 0 : if ( IsJoinLocked() )
1038 0 : return;
1039 :
1040 : OSL_ENSURE( !((SwTxtFrm*)this)->IsSwapped(), "Calculation of a swapped frame" );
1041 :
1042 0 : StackHack aHack;
1043 :
1044 0 : if ( ((SwTxtFrm*)this)->IsLocked() )
1045 : {
1046 : OSL_FAIL( "Format for locked TxtFrm." );
1047 0 : return;
1048 : }
1049 :
1050 0 : LockJoin();
1051 0 : long nFormatCount = 0;
1052 : // - loop prevention
1053 0 : int nConsequetiveFormatsWithoutChange = 0;
1054 : PROTOCOL_ENTER( this, PROT_MAKEALL, 0, 0 )
1055 :
1056 : #ifdef DBG_UTIL
1057 : const SwDoc *pDoc = GetAttrSet()->GetDoc();
1058 : if( pDoc )
1059 : {
1060 : static bool bWarned = false;
1061 : if( pDoc->InXMLExport() )
1062 : {
1063 : SAL_WARN_IF( !bWarned, "sw", "Formatting during XML-export!" );
1064 : bWarned = true;
1065 : }
1066 : else
1067 : bWarned = false;
1068 : }
1069 : #endif
1070 :
1071 : // takes care of the notification in the dtor
1072 0 : SwCntntNotify *pNotify = new SwCntntNotify( this );
1073 :
1074 : // as long as bMakePage is true, a new page can be created (exactly once)
1075 0 : bool bMakePage = true;
1076 : // bMovedBwd gets set to true when the frame flows backwards
1077 0 : bool bMovedBwd = false;
1078 : // as long as bMovedFwd is false, the Frm may flow backwards (until
1079 : // it has been moved forward once)
1080 0 : bool bMovedFwd = false;
1081 0 : sal_Bool bFormatted = sal_False; // For the widow/orphan rules, we encourage the
1082 : // last CntntFrm of a chain to format. This only
1083 : // needs to happen once. Every time the Frm is
1084 : // moved, the flag will have to be reset.
1085 0 : bool bMustFit = false; // Once the emergency brake is pulled,
1086 : // no other prepares will be triggered
1087 0 : bool bFitPromise = false; // If a paragraph didn't fit, but promises
1088 : // with WouldFit that it would adjust accordingly,
1089 : // this flag is set. If it turns out that it
1090 : // didn't keep it's promise, we can act in a
1091 : // controlled fashion.
1092 : bool bMoveable;
1093 0 : const sal_Bool bFly = IsInFly();
1094 0 : const sal_Bool bTab = IsInTab();
1095 0 : const sal_Bool bFtn = IsInFtn();
1096 0 : const sal_Bool bSct = IsInSct();
1097 0 : Point aOldFrmPos; // This is so we can compare with the last pos
1098 0 : Point aOldPrtPos; // and determine whether it makes sense to Prepare
1099 :
1100 0 : SwBorderAttrAccess aAccess( SwFrm::GetCache(), this );
1101 0 : const SwBorderAttrs &rAttrs = *aAccess.Get();
1102 :
1103 : // OD 2004-02-26 #i25029#
1104 0 : if ( !IsFollow() && rAttrs.JoinedWithPrev( *(this) ) )
1105 : {
1106 0 : pNotify->SetBordersJoinedWithPrev();
1107 : }
1108 :
1109 0 : const sal_Bool bKeep = IsKeep( rAttrs.GetAttrSet() );
1110 :
1111 0 : SwSaveFtnHeight *pSaveFtn = 0;
1112 0 : if ( bFtn )
1113 : {
1114 0 : SwFtnFrm *pFtn = FindFtnFrm();
1115 0 : SwSectionFrm* pSct = pFtn->FindSctFrm();
1116 0 : if ( !((SwTxtFrm*)pFtn->GetRef())->IsLocked() )
1117 : {
1118 0 : SwFtnBossFrm* pBoss = pFtn->GetRef()->FindFtnBossFrm(
1119 0 : pFtn->GetAttr()->GetFtn().IsEndNote() );
1120 0 : if( !pSct || pSct->IsColLocked() || !pSct->Growable() )
1121 : pSaveFtn = new SwSaveFtnHeight( pBoss,
1122 0 : ((SwTxtFrm*)pFtn->GetRef())->GetFtnLine( pFtn->GetAttr() ) );
1123 : }
1124 : }
1125 :
1126 0 : if ( GetUpper()->IsSctFrm() &&
1127 0 : HasFollow() &&
1128 0 : GetFollow()->GetFrm() == GetNext() )
1129 : {
1130 0 : dynamic_cast<SwTxtFrm*>(this)->JoinFrm();
1131 : }
1132 :
1133 : // #i28701# - move master forward, if it has to move,
1134 : // because of its object positioning.
1135 0 : if ( !static_cast<SwTxtFrm*>(this)->IsFollow() )
1136 : {
1137 0 : sal_uInt32 nToPageNum = 0L;
1138 : const bool bMoveFwdByObjPos = SwLayouter::FrmMovedFwdByObjPos(
1139 0 : *(GetAttrSet()->GetDoc()),
1140 : *(static_cast<SwTxtFrm*>(this)),
1141 0 : nToPageNum );
1142 : // #i58182#
1143 : // Also move a paragraph forward, which is the first one inside a table cell.
1144 0 : if ( bMoveFwdByObjPos &&
1145 0 : FindPageFrm()->GetPhyPageNum() < nToPageNum &&
1146 0 : ( lcl_Prev( this ) ||
1147 0 : GetUpper()->IsCellFrm() ||
1148 0 : ( GetUpper()->IsSctFrm() &&
1149 0 : GetUpper()->GetUpper()->IsCellFrm() ) ) &&
1150 0 : IsMoveable() )
1151 : {
1152 0 : bMovedFwd = true;
1153 0 : MoveFwd( bMakePage, sal_False );
1154 : }
1155 : }
1156 :
1157 : // If a Follow sits next to it's Master and doesn't fit, we know it can
1158 : // be moved right now.
1159 0 : if ( lcl_Prev( this ) && ((SwTxtFrm*)this)->IsFollow() && IsMoveable() )
1160 : {
1161 0 : bMovedFwd = true;
1162 : // OD 2004-03-02 #106629# - If follow frame is in table, it's master
1163 : // will be the last in the current table cell. Thus, invalidate the
1164 : // printing area of the master,
1165 0 : if ( IsInTab() )
1166 : {
1167 0 : lcl_Prev( this )->InvalidatePrt();
1168 : }
1169 0 : MoveFwd( bMakePage, sal_False );
1170 : }
1171 :
1172 : // OD 08.11.2002 #104840# - check footnote content for forward move.
1173 : // If a content of a footnote is on a prior page/column as its invalid
1174 : // reference, it can be moved forward.
1175 0 : if ( bFtn && !mbValidPos )
1176 : {
1177 0 : SwFtnFrm* pFtn = FindFtnFrm();
1178 0 : SwCntntFrm* pRefCnt = pFtn ? pFtn->GetRef() : 0;
1179 0 : if ( pRefCnt && !pRefCnt->IsValid() )
1180 : {
1181 0 : SwFtnBossFrm* pFtnBossOfFtn = pFtn->FindFtnBossFrm();
1182 0 : SwFtnBossFrm* pFtnBossOfRef = pRefCnt->FindFtnBossFrm();
1183 : //<loop of movefwd until condition held or no move>
1184 0 : if ( pFtnBossOfFtn && pFtnBossOfRef &&
1185 0 : pFtnBossOfFtn != pFtnBossOfRef &&
1186 0 : pFtnBossOfFtn->IsBefore( pFtnBossOfRef ) )
1187 : {
1188 0 : bMovedFwd = true;
1189 0 : MoveFwd( bMakePage, sal_False );
1190 : }
1191 : }
1192 : }
1193 :
1194 0 : SWRECTFN( this )
1195 :
1196 0 : while ( !mbValidPos || !mbValidSize || !mbValidPrtArea )
1197 : {
1198 : // - loop prevention
1199 0 : SwRect aOldFrm_StopFormat( Frm() );
1200 0 : SwRect aOldPrt_StopFormat( Prt() );
1201 0 : if ( (bMoveable = IsMoveable()) )
1202 : {
1203 0 : SwFrm *pPre = GetIndPrev();
1204 0 : if ( CheckMoveFwd( bMakePage, bKeep, bMovedBwd ) )
1205 : {
1206 0 : SWREFRESHFN( this )
1207 0 : bMovedFwd = true;
1208 0 : if ( bMovedBwd )
1209 : {
1210 : // While flowing back, the Upper was encouraged to
1211 : // completely re-paint itself. We can skip this now after
1212 : // flowing back and forth.
1213 0 : GetUpper()->ResetCompletePaint();
1214 : // The predecessor was invalidated, so this is obsolete as well now.
1215 : OSL_ENSURE( pPre, "missing old Prev" );
1216 0 : if( !pPre->IsSctFrm() )
1217 0 : ::ValidateSz( pPre );
1218 : }
1219 0 : bMoveable = IsMoveable();
1220 : }
1221 : }
1222 :
1223 0 : aOldFrmPos = (Frm().*fnRect->fnGetPos)();
1224 0 : aOldPrtPos = (Prt().*fnRect->fnGetPos)();
1225 :
1226 0 : if ( !mbValidPos )
1227 0 : MakePos();
1228 :
1229 : //Set FixSize. VarSize is being adjusted by Format().
1230 0 : if ( !mbValidSize )
1231 : {
1232 : // #125452#
1233 : // invalidate printing area flag, if the following conditions are hold:
1234 : // - current frame width is 0.
1235 : // - current printing area width is 0.
1236 : // - frame width is adjusted to a value greater than 0.
1237 : // - printing area flag is sal_True.
1238 : // Thus, it's assured that the printing area is adjusted, if the
1239 : // frame area width changes its width from 0 to something greater
1240 : // than 0.
1241 : // Note: A text frame can be in such a situation, if the format is
1242 : // triggered by method call <SwCrsrShell::SetCrsr()> after
1243 : // loading the document.
1244 0 : const SwTwips nNewFrmWidth = (GetUpper()->Prt().*fnRect->fnGetWidth)();
1245 0 : if ( mbValidPrtArea && nNewFrmWidth > 0 &&
1246 0 : (Frm().*fnRect->fnGetWidth)() == 0 &&
1247 0 : (Prt().*fnRect->fnGetWidth)() == 0 )
1248 : {
1249 0 : mbValidPrtArea = sal_False;
1250 : }
1251 :
1252 0 : (Frm().*fnRect->fnSetWidth)( nNewFrmWidth );
1253 :
1254 : // When a lower of a vertically aligned fly frame changes its size we need to recalculate content pos.
1255 0 : if( GetUpper() && GetUpper()->IsFlyFrm() &&
1256 0 : GetUpper()->GetFmt()->GetTextVertAdjust().GetValue() != SDRTEXTVERTADJUST_TOP )
1257 : {
1258 0 : static_cast<SwFlyFrm*>(GetUpper())->InvalidateContentPos();
1259 0 : GetUpper()->SetCompletePaint();
1260 : }
1261 : }
1262 0 : if ( !mbValidPrtArea )
1263 : {
1264 0 : const long nOldW = (Prt().*fnRect->fnGetWidth)();
1265 : // #i34730# - keep current frame height
1266 0 : const SwTwips nOldH = (Frm().*fnRect->fnGetHeight)();
1267 0 : MakePrtArea( rAttrs );
1268 0 : if ( nOldW != (Prt().*fnRect->fnGetWidth)() )
1269 0 : Prepare( PREP_FIXSIZE_CHG );
1270 : // #i34730# - check, if frame height has changed.
1271 : // If yes, send a PREP_ADJUST_FRM and invalidate the size flag to
1272 : // force a format. The format will check in its method
1273 : // <SwTxtFrm::CalcPreps()>, if the already formatted lines still
1274 : // fit and if not, performs necessary actions.
1275 : // #i40150# - no check, if frame is undersized.
1276 0 : if ( mbValidSize && !IsUndersized() &&
1277 0 : nOldH != (Frm().*fnRect->fnGetHeight)() )
1278 : {
1279 : // #115759# - no PREP_ADJUST_FRM and size
1280 : // invalidation, if height decreases only by the additional
1281 : // lower space as last content of a table cell and an existing
1282 : // follow containing one line exists.
1283 0 : const SwTwips nHDiff = nOldH - (Frm().*fnRect->fnGetHeight)();
1284 : const bool bNoPrepAdjustFrm =
1285 0 : nHDiff > 0 && IsInTab() && GetFollow() &&
1286 0 : ( 1 == static_cast<SwTxtFrm*>(GetFollow())->GetLineCount( COMPLETE_STRING ) || (static_cast<SwTxtFrm*>(GetFollow())->Frm().*fnRect->fnGetWidth)() < 0 ) &&
1287 0 : GetFollow()->CalcAddLowerSpaceAsLastInTableCell() == nHDiff;
1288 0 : if ( !bNoPrepAdjustFrm )
1289 : {
1290 0 : Prepare( PREP_ADJUST_FRM );
1291 0 : mbValidSize = sal_False;
1292 : }
1293 : }
1294 : }
1295 :
1296 : // To make the widow and orphan rules work, we need to notify the CntntFrm.
1297 : // Criteria:
1298 : // - It needs to be movable (otherwise, splitting doesn't make sense)
1299 : // - It needs to overlap with the lower edge of the PrtArea of the Upper
1300 0 : if ( !bMustFit )
1301 : {
1302 0 : sal_Bool bWidow = sal_True;
1303 0 : const SwTwips nDeadLine = (GetUpper()->*fnRect->fnGetPrtBottom)();
1304 0 : if ( bMoveable && !bFormatted && ( GetFollow() ||
1305 0 : ( (Frm().*fnRect->fnOverStep)( nDeadLine ) ) ) )
1306 : {
1307 0 : Prepare( PREP_WIDOWS_ORPHANS, 0, false );
1308 0 : mbValidSize = bWidow = sal_False;
1309 : }
1310 0 : if( (Frm().*fnRect->fnGetPos)() != aOldFrmPos ||
1311 0 : (Prt().*fnRect->fnGetPos)() != aOldPrtPos )
1312 : {
1313 : // In this Prepare, an _InvalidateSize() might happen.
1314 : // mbValidSize becomes sal_False and Format() gets called.
1315 0 : Prepare( PREP_POS_CHGD, (const void*)&bFormatted, false );
1316 0 : if ( bWidow && GetFollow() )
1317 : {
1318 0 : Prepare( PREP_WIDOWS_ORPHANS, 0, false );
1319 0 : mbValidSize = sal_False;
1320 : }
1321 : }
1322 : }
1323 0 : if ( !mbValidSize )
1324 : {
1325 0 : mbValidSize = bFormatted = sal_True;
1326 0 : ++nFormatCount;
1327 0 : if( nFormatCount > STOP_FLY_FORMAT )
1328 0 : SetFlyLock( sal_True );
1329 : // - loop prevention
1330 : // No format any longer, if <cnStopFormat> consequetive formats
1331 : // without change occur.
1332 0 : if ( nConsequetiveFormatsWithoutChange <= cnStopFormat )
1333 : {
1334 0 : Format();
1335 : }
1336 : #if OSL_DEBUG_LEVEL > 0
1337 : else
1338 : {
1339 : OSL_FAIL( "debug assertion: <SwCntntFrm::MakeAll()> - format of text frame suppressed by fix b6448963" );
1340 : }
1341 : #endif
1342 : }
1343 :
1344 : // If this is the first one in a chain, check if this can flow
1345 : // backwards (if this is movable at all).
1346 : // To prevent oscillations/loops, check that this has not just
1347 : // flowed forwards.
1348 : bool bDummy;
1349 0 : if ( !lcl_Prev( this ) &&
1350 0 : !bMovedFwd &&
1351 0 : ( bMoveable || ( bFly && !bTab ) ) &&
1352 0 : ( !bFtn || !GetUpper()->FindFtnFrm()->GetPrev() )
1353 0 : && MoveBwd( bDummy ) )
1354 : {
1355 0 : SWREFRESHFN( this )
1356 0 : bMovedBwd = true;
1357 0 : bFormatted = sal_False;
1358 0 : if ( bKeep && bMoveable )
1359 : {
1360 0 : if( CheckMoveFwd( bMakePage, sal_False, bMovedBwd ) )
1361 : {
1362 0 : bMovedFwd = true;
1363 0 : bMoveable = IsMoveable();
1364 0 : SWREFRESHFN( this )
1365 : }
1366 0 : Point aOldPos = (Frm().*fnRect->fnGetPos)();
1367 0 : MakePos();
1368 0 : if( aOldPos != (Frm().*fnRect->fnGetPos)() )
1369 : {
1370 0 : Prepare( PREP_POS_CHGD, (const void*)&bFormatted, false );
1371 0 : if ( !mbValidSize )
1372 : {
1373 0 : (Frm().*fnRect->fnSetWidth)( (GetUpper()->
1374 0 : Prt().*fnRect->fnGetWidth)() );
1375 0 : if ( !mbValidPrtArea )
1376 : {
1377 0 : const long nOldW = (Prt().*fnRect->fnGetWidth)();
1378 0 : MakePrtArea( rAttrs );
1379 0 : if( nOldW != (Prt().*fnRect->fnGetWidth)() )
1380 0 : Prepare( PREP_FIXSIZE_CHG, 0, false );
1381 : }
1382 0 : if( GetFollow() )
1383 0 : Prepare( PREP_WIDOWS_ORPHANS, 0, false );
1384 0 : mbValidSize = bFormatted = sal_True;
1385 0 : Format();
1386 : }
1387 : }
1388 0 : SwFrm *pNxt = HasFollow() ? NULL : FindNext();
1389 0 : while( pNxt && pNxt->IsSctFrm() )
1390 : { // Leave empty sections out, go into the other ones.
1391 0 : if( ((SwSectionFrm*)pNxt)->GetSection() )
1392 : {
1393 0 : SwFrm* pTmp = ((SwSectionFrm*)pNxt)->ContainsAny();
1394 0 : if( pTmp )
1395 : {
1396 0 : pNxt = pTmp;
1397 0 : break;
1398 : }
1399 : }
1400 0 : pNxt = pNxt->FindNext();
1401 : }
1402 0 : if ( pNxt )
1403 : {
1404 0 : pNxt->Calc();
1405 0 : if( mbValidPos && !GetIndNext() )
1406 : {
1407 0 : SwSectionFrm *pSct = FindSctFrm();
1408 0 : if( pSct && !pSct->GetValidSizeFlag() )
1409 : {
1410 0 : SwSectionFrm* pNxtSct = pNxt->FindSctFrm();
1411 0 : if( pNxtSct && pSct->IsAnFollow( pNxtSct ) )
1412 0 : mbValidPos = sal_False;
1413 : }
1414 : else
1415 0 : mbValidPos = sal_False;
1416 : }
1417 : }
1418 : }
1419 : }
1420 :
1421 : // In footnotes, the TxtFrm may validate itself, which can lead to the
1422 : // situation that it's position is wrong despite being "valid".
1423 0 : if ( mbValidPos )
1424 : {
1425 : // #i59341#
1426 : // Workaround for inadequate layout algorithm:
1427 : // suppress invalidation and calculation of position, if paragraph
1428 : // has formatted itself at least STOP_FLY_FORMAT times and
1429 : // has anchored objects.
1430 : // Thus, the anchored objects get the possibility to format itself
1431 : // and this probably solve the layout loop.
1432 0 : if ( bFtn &&
1433 0 : nFormatCount <= STOP_FLY_FORMAT &&
1434 0 : !GetDrawObjs() )
1435 : {
1436 0 : mbValidPos = sal_False;
1437 0 : MakePos();
1438 0 : aOldFrmPos = (Frm().*fnRect->fnGetPos)();
1439 0 : aOldPrtPos = (Prt().*fnRect->fnGetPos)();
1440 : }
1441 : }
1442 :
1443 : // - loop prevention
1444 : {
1445 0 : if ( aOldFrm_StopFormat == Frm() &&
1446 0 : aOldPrt_StopFormat == Prt() )
1447 : {
1448 0 : ++nConsequetiveFormatsWithoutChange;
1449 : }
1450 : else
1451 : {
1452 0 : nConsequetiveFormatsWithoutChange = 0;
1453 : }
1454 : }
1455 :
1456 : // Yet again an invalid value? Repeat from the start...
1457 0 : if ( !mbValidPos || !mbValidSize || !mbValidPrtArea )
1458 0 : continue;
1459 :
1460 : // Done?
1461 : // Attention: because height == 0, it's better to use Top()+Height() instead of
1462 : // Bottom(). This might happen with undersized TextFrms on the lower edge of a
1463 : // multi-column section
1464 0 : const long nPrtBottom = (GetUpper()->*fnRect->fnGetPrtBottom)();
1465 0 : const long nBottomDist = (Frm().*fnRect->fnBottomDist)( nPrtBottom );
1466 0 : if( nBottomDist >= 0 )
1467 : {
1468 0 : if ( bKeep && bMoveable )
1469 : {
1470 : // We make sure the successor will be formatted the same.
1471 : // This way, we keep control until (almost) everything is stable,
1472 : // allowing us to avoid endless loops caused by ever repeating
1473 : // retries.
1474 :
1475 : // bMoveFwdInvalid is required for #38407#. This was originally solved
1476 : // in flowfrm.cxx rev 1.38, but broke the above schema and
1477 : // preferred to play towers of hanoi (#43669#).
1478 0 : SwFrm *pNxt = HasFollow() ? NULL : FindNext();
1479 : // For sections we prefer the content, because it can change
1480 : // the page if required.
1481 0 : while( pNxt && pNxt->IsSctFrm() )
1482 : {
1483 0 : if( ((SwSectionFrm*)pNxt)->GetSection() )
1484 : {
1485 0 : pNxt = ((SwSectionFrm*)pNxt)->ContainsAny();
1486 0 : break;
1487 : }
1488 0 : pNxt = pNxt->FindNext();
1489 : }
1490 0 : if ( pNxt )
1491 : {
1492 0 : const bool bMoveFwdInvalid = 0 != GetIndNext();
1493 : const bool bNxtNew =
1494 0 : ( 0 == (pNxt->Prt().*fnRect->fnGetHeight)() ) &&
1495 0 : (!pNxt->IsTxtFrm() ||!((SwTxtFrm*)pNxt)->IsHiddenNow());
1496 :
1497 0 : pNxt->Calc();
1498 :
1499 0 : if ( !bMovedBwd &&
1500 0 : ((bMoveFwdInvalid && !GetIndNext()) ||
1501 : bNxtNew) )
1502 : {
1503 0 : if( bMovedFwd )
1504 0 : pNotify->SetInvaKeep();
1505 0 : bMovedFwd = false;
1506 : }
1507 : }
1508 : }
1509 0 : continue;
1510 : }
1511 :
1512 : // I don't fit into my parents, so it's time to make changes
1513 : // as constructively as possible.
1514 :
1515 : //If I'm NOT allowed to leave the parent Frm, I've got a problem.
1516 : // Following Arthur Dent, we do the only thing that you can do with
1517 : // an unsolvable problem: We ignore it with all our power.
1518 0 : if ( !bMoveable || IsUndersized() )
1519 : {
1520 0 : if( !bMoveable && IsInTab() )
1521 : {
1522 0 : long nDiff = -(Frm().*fnRect->fnBottomDist)(
1523 0 : (GetUpper()->*fnRect->fnGetPrtBottom)() );
1524 0 : long nReal = GetUpper()->Grow( nDiff );
1525 0 : if( nReal )
1526 0 : continue;
1527 : }
1528 0 : break;
1529 : }
1530 :
1531 : // If there's no way I can make myself fit into my Upper, the situation
1532 : // could still probably be mitigated by splitting up.
1533 : // This situation arises with freshly created Follows that had been moved
1534 : // to the next page but is still too big for it - ie. needs to be split
1535 : // as well.
1536 :
1537 : // If I'm unable to split (WouldFit()) and can't be fitted, I'm going
1538 : // to tell my TxtFrm part that, if possible, we still need to split despite
1539 : // the "don't split" attribute.
1540 0 : bool bMoveOrFit = false;
1541 0 : bool bDontMoveMe = !GetIndPrev();
1542 0 : if( bDontMoveMe && IsInSct() )
1543 : {
1544 0 : SwFtnBossFrm* pBoss = FindFtnBossFrm();
1545 0 : bDontMoveMe = !pBoss->IsInSct() ||
1546 0 : ( !pBoss->Lower()->GetNext() && !pBoss->GetPrev() );
1547 : }
1548 :
1549 : // Finally, we are able to split table rows. Therefore, bDontMoveMe
1550 : // can be set to false:
1551 0 : if( bDontMoveMe && IsInTab() &&
1552 0 : 0 != const_cast<SwCntntFrm*>(this)->GetNextCellLeaf( MAKEPAGE_NONE ) )
1553 0 : bDontMoveMe = false;
1554 :
1555 0 : if ( bDontMoveMe && (Frm().*fnRect->fnGetHeight)() >
1556 0 : (GetUpper()->Prt().*fnRect->fnGetHeight)() )
1557 : {
1558 0 : if ( !bFitPromise )
1559 : {
1560 0 : SwTwips nTmp = (GetUpper()->Prt().*fnRect->fnGetHeight)() -
1561 0 : (Prt().*fnRect->fnGetTop)();
1562 0 : bool bSplit = !IsFwdMoveAllowed();
1563 0 : if ( nTmp > 0 && WouldFit( nTmp, bSplit, false ) )
1564 : {
1565 0 : Prepare( PREP_WIDOWS_ORPHANS, 0, false );
1566 0 : mbValidSize = sal_False;
1567 0 : bFitPromise = true;
1568 0 : continue;
1569 : }
1570 : /* --------------------------------------------------
1571 : * In earlier days, we never tried to fit TextFrms in
1572 : * frames and sections using bMoveOrFit by ignoring
1573 : * its attributes (Widows, Keep).
1574 : * This should have been done at least for column frames;
1575 : * as it must be tried anyway with linked frames and sections.
1576 : * Exception: If we sit in FormatWidthCols, we must not ignore
1577 : * the attributes.
1578 : * --------------------------------------------------*/
1579 0 : else if ( !bFtn && bMoveable &&
1580 0 : ( !bFly || !FindFlyFrm()->IsColLocked() ) &&
1581 0 : ( !bSct || !FindSctFrm()->IsColLocked() ) )
1582 0 : bMoveOrFit = true;
1583 : }
1584 : #if OSL_DEBUG_LEVEL > 0
1585 : else
1586 : {
1587 : OSL_FAIL( "+TxtFrm didn't respect WouldFit promise." );
1588 : }
1589 : #endif
1590 : }
1591 :
1592 : // Let's see if I can find some space somewhere...
1593 : // footnotes in the neighbourhood are moved into _MoveFtnCntFwd
1594 0 : SwFrm *pPre = GetIndPrev();
1595 0 : SwFrm *pOldUp = GetUpper();
1596 :
1597 : /* MA 13. Oct. 98: What is this supposed to be!?
1598 : * AMA 14. Dec 98: If a column section can't find any space for its first ContentFrm, it should be
1599 : * moved not only to the next column, but probably even to the next page, creating
1600 : * a section-follow there.
1601 : */
1602 0 : if( IsInSct() && bMovedFwd && bMakePage && pOldUp->IsColBodyFrm() &&
1603 0 : pOldUp->GetUpper()->GetUpper()->IsSctFrm() &&
1604 0 : ( pPre || pOldUp->GetUpper()->GetPrev() ) &&
1605 0 : ((SwSectionFrm*)pOldUp->GetUpper()->GetUpper())->MoveAllowed(this) )
1606 : {
1607 0 : bMovedFwd = false;
1608 : }
1609 :
1610 0 : const sal_Bool bCheckForGrownBody = pOldUp->IsBodyFrm();
1611 0 : const long nOldBodyHeight = (pOldUp->Frm().*fnRect->fnGetHeight)();
1612 :
1613 0 : if ( !bMovedFwd && !MoveFwd( bMakePage, sal_False ) )
1614 0 : bMakePage = false;
1615 0 : SWREFRESHFN( this )
1616 :
1617 : // If MoveFwd moves the paragraph to the next page, a following
1618 : // paragraph, which contains footnotes can can cause the old upper
1619 : // frame to grow. In this case we explicitly allow a new check
1620 : // for MoveBwd. Robust: We also check the bMovedBwd flag again.
1621 : // If pOldUp was a footnote frame, it has been deleted inside MoveFwd.
1622 : // Therefore we only check for growing body frames.
1623 0 : if ( bCheckForGrownBody && ! bMovedBwd && pOldUp != GetUpper() &&
1624 0 : (pOldUp->Frm().*fnRect->fnGetHeight)() > nOldBodyHeight )
1625 : {
1626 0 : bMovedFwd = false;
1627 : }
1628 : else
1629 : {
1630 0 : bMovedFwd = true;
1631 : }
1632 :
1633 0 : bFormatted = sal_False;
1634 0 : if ( bMoveOrFit && GetUpper() == pOldUp )
1635 : {
1636 : // FME 2007-08-30 #i81146# new loop control
1637 0 : if ( nConsequetiveFormatsWithoutChange <= cnStopFormat )
1638 : {
1639 0 : Prepare( PREP_MUST_FIT, 0, false );
1640 0 : mbValidSize = sal_False;
1641 0 : bMustFit = true;
1642 0 : continue;
1643 : }
1644 :
1645 : #if OSL_DEBUG_LEVEL > 0
1646 : OSL_FAIL( "LoopControl in SwCntntFrm::MakeAll" );
1647 : #endif
1648 : }
1649 0 : if ( bMovedBwd && GetUpper() )
1650 : { // Retire invalidations that have become useless.
1651 0 : GetUpper()->ResetCompletePaint();
1652 0 : if( pPre && !pPre->IsSctFrm() )
1653 0 : ::ValidateSz( pPre );
1654 : }
1655 :
1656 : } //while ( !mbValidPos || !mbValidSize || !mbValidPrtArea )
1657 :
1658 : // NEW: Looping Louie (Light). Should not be applied in balanced sections.
1659 : // Should only be applied if there is no better solution!
1660 0 : LOOPING_LOUIE_LIGHT( bMovedFwd && bMovedBwd && !IsInBalancedSection() &&
1661 : (
1662 :
1663 : // #118572#
1664 0 : ( bFtn && !FindFtnFrm()->GetRef()->IsInSct() ) ||
1665 :
1666 : // #i33887#
1667 0 : ( IsInSct() && bKeep )
1668 :
1669 : // ... add your conditions here ...
1670 :
1671 : ),
1672 0 : static_cast<SwTxtFrm&>(*this) );
1673 :
1674 0 : delete pSaveFtn;
1675 :
1676 0 : UnlockJoin();
1677 0 : if ( bMovedFwd || bMovedBwd )
1678 0 : pNotify->SetInvaKeep();
1679 : // OD 2004-02-26 #i25029#
1680 0 : if ( bMovedFwd )
1681 : {
1682 0 : pNotify->SetInvalidatePrevPrtArea();
1683 : }
1684 0 : delete pNotify;
1685 0 : SetFlyLock( sal_False );
1686 : }
1687 :
1688 0 : void MakeNxt( SwFrm *pFrm, SwFrm *pNxt )
1689 : {
1690 : // fix(25455): Validate, otherwise this leads to a recursion.
1691 : // The first try, cancelling with pFrm = 0 if !Valid, leads to a problem, as
1692 : // the Keep may not be considered properly anymore (27417).
1693 0 : const sal_Bool bOldPos = pFrm->GetValidPosFlag();
1694 0 : const sal_Bool bOldSz = pFrm->GetValidSizeFlag();
1695 0 : const sal_Bool bOldPrt = pFrm->GetValidPrtAreaFlag();
1696 0 : pFrm->mbValidPos = pFrm->mbValidPrtArea = pFrm->mbValidSize = sal_True;
1697 :
1698 : // fix(29272): Don't call MakeAll - there, pFrm might be invalidated again, and
1699 : // we recursively end up in here again.
1700 0 : if ( pNxt->IsCntntFrm() )
1701 : {
1702 0 : SwCntntNotify aNotify( (SwCntntFrm*)pNxt );
1703 0 : SwBorderAttrAccess aAccess( SwFrm::GetCache(), pNxt );
1704 0 : const SwBorderAttrs &rAttrs = *aAccess.Get();
1705 0 : if ( !pNxt->GetValidSizeFlag() )
1706 : {
1707 0 : if( pNxt->IsVertical() )
1708 0 : pNxt->Frm().Height( pNxt->GetUpper()->Prt().Height() );
1709 : else
1710 0 : pNxt->Frm().Width( pNxt->GetUpper()->Prt().Width() );
1711 : }
1712 0 : ((SwCntntFrm*)pNxt)->MakePrtArea( rAttrs );
1713 0 : pNxt->Format( &rAttrs );
1714 : }
1715 : else
1716 : {
1717 0 : SwLayNotify aNotify( (SwLayoutFrm*)pNxt );
1718 0 : SwBorderAttrAccess aAccess( SwFrm::GetCache(), pNxt );
1719 0 : const SwBorderAttrs &rAttrs = *aAccess.Get();
1720 0 : if ( !pNxt->GetValidSizeFlag() )
1721 : {
1722 0 : if( pNxt->IsVertical() )
1723 0 : pNxt->Frm().Height( pNxt->GetUpper()->Prt().Height() );
1724 : else
1725 0 : pNxt->Frm().Width( pNxt->GetUpper()->Prt().Width() );
1726 : }
1727 0 : pNxt->Format( &rAttrs );
1728 : }
1729 :
1730 0 : pFrm->mbValidPos = bOldPos;
1731 0 : pFrm->mbValidSize = bOldSz;
1732 0 : pFrm->mbValidPrtArea = bOldPrt;
1733 0 : }
1734 :
1735 : /// This routine checks whether there are no other FtnBosses
1736 : /// between the pFrm's FtnBoss and the pNxt's FtnBoss.
1737 0 : static bool lcl_IsNextFtnBoss( const SwFrm *pFrm, const SwFrm* pNxt )
1738 : {
1739 : OSL_ENSURE( pFrm && pNxt, "lcl_IsNextFtnBoss: No Frames?" );
1740 0 : pFrm = pFrm->FindFtnBossFrm();
1741 0 : pNxt = pNxt->FindFtnBossFrm();
1742 : // If pFrm is a last column, we use the page instead.
1743 0 : while( pFrm && pFrm->IsColumnFrm() && !pFrm->GetNext() )
1744 0 : pFrm = pFrm->GetUpper()->FindFtnBossFrm();
1745 : // If pNxt is a first column, we use the page instead.
1746 0 : while( pNxt && pNxt->IsColumnFrm() && !pNxt->GetPrev() )
1747 0 : pNxt = pNxt->GetUpper()->FindFtnBossFrm();
1748 : // So.. now pFrm and pNxt are either two adjacent pages or columns.
1749 0 : return pFrm && pNxt && pFrm->GetNext() == pNxt;
1750 : }
1751 :
1752 0 : sal_Bool SwCntntFrm::_WouldFit( SwTwips nSpace,
1753 : SwLayoutFrm *pNewUpper,
1754 : sal_Bool bTstMove,
1755 : const bool bObjsInNewUpper )
1756 : {
1757 : // To have the footnote select it's place carefully, it needs
1758 : // to be moved in any case if there is at least one page/column
1759 : // between the footnote and the new Upper.
1760 0 : SwFtnFrm* pFtnFrm = 0;
1761 0 : if ( IsInFtn() )
1762 : {
1763 0 : if( !lcl_IsNextFtnBoss( pNewUpper, this ) )
1764 0 : return sal_True;
1765 0 : pFtnFrm = FindFtnFrm();
1766 : }
1767 :
1768 : sal_Bool bRet;
1769 0 : bool bSplit = !pNewUpper->Lower();
1770 0 : SwCntntFrm *pFrm = this;
1771 0 : const SwFrm *pTmpPrev = pNewUpper->Lower();
1772 0 : if( pTmpPrev && pTmpPrev->IsFtnFrm() )
1773 0 : pTmpPrev = ((SwFtnFrm*)pTmpPrev)->Lower();
1774 0 : while ( pTmpPrev && pTmpPrev->GetNext() )
1775 0 : pTmpPrev = pTmpPrev->GetNext();
1776 0 : do
1777 : {
1778 : // #i46181#
1779 0 : SwTwips nSecondCheck = 0;
1780 0 : SwTwips nOldSpace = nSpace;
1781 0 : bool bOldSplit = bSplit;
1782 :
1783 0 : if ( bTstMove || IsInFly() || ( IsInSct() &&
1784 0 : ( pFrm->GetUpper()->IsColBodyFrm() || ( pFtnFrm &&
1785 0 : pFtnFrm->GetUpper()->GetUpper()->IsColumnFrm() ) ) ) )
1786 : {
1787 : // This is going to get a bit insidious now. If you're faint of heart,
1788 : // you'd better look away here. If a Fly contains columns, then the Cntnts
1789 : // are movable, except ones in the last column (see SwFrm::IsMoveable()).
1790 : // Of course they're allowed to float back. WouldFit() only returns a usable
1791 : // value if the Frm is movable. To fool WouldFit() into believing there's
1792 : // a movable Frm, I'm just going to hang it somewhere else for the time.
1793 : // The same procedure applies for column sections to make SwSectionFrm::Growable()
1794 : // return the proper value.
1795 : // Within footnotes, we may even need to put the SwFtnFrm somewhere else, if
1796 : // there's no SwFtnFrm there.
1797 0 : SwFrm* pTmpFrm = pFrm->IsInFtn() && !pNewUpper->FindFtnFrm() ?
1798 0 : (SwFrm*)pFrm->FindFtnFrm() : pFrm;
1799 0 : SwLayoutFrm *pUp = pTmpFrm->GetUpper();
1800 0 : SwFrm *pOldNext = pTmpFrm->GetNext();
1801 0 : pTmpFrm->Remove();
1802 0 : pTmpFrm->InsertBefore( pNewUpper, 0 );
1803 0 : if ( pFrm->IsTxtFrm() &&
1804 0 : ( bTstMove ||
1805 0 : ((SwTxtFrm*)pFrm)->HasFollow() ||
1806 0 : ( !((SwTxtFrm*)pFrm)->HasPara() &&
1807 0 : !((SwTxtFrm*)pFrm)->IsEmpty()
1808 : )
1809 : )
1810 : )
1811 : {
1812 0 : bTstMove = sal_True;
1813 0 : bRet = ((SwTxtFrm*)pFrm)->TestFormat( pTmpPrev, nSpace, bSplit );
1814 : }
1815 : else
1816 0 : bRet = pFrm->WouldFit( nSpace, bSplit, false );
1817 :
1818 0 : pTmpFrm->Remove();
1819 0 : pTmpFrm->InsertBefore( pUp, pOldNext );
1820 : }
1821 : else
1822 : {
1823 0 : bRet = pFrm->WouldFit( nSpace, bSplit, false );
1824 0 : nSecondCheck = !bSplit ? 1 : 0;
1825 : }
1826 :
1827 0 : SwBorderAttrAccess aAccess( SwFrm::GetCache(), pFrm );
1828 0 : const SwBorderAttrs &rAttrs = *aAccess.Get();
1829 :
1830 : // Sad but true: We need to consider the spacing in our calculation.
1831 : // This already happened in TestFormat.
1832 0 : if ( bRet && !bTstMove )
1833 : {
1834 : SwTwips nUpper;
1835 :
1836 0 : if ( pTmpPrev )
1837 : {
1838 0 : nUpper = CalcUpperSpace( NULL, pTmpPrev );
1839 :
1840 : // in balanced columned section frames we do not want the
1841 : // common border
1842 0 : sal_Bool bCommonBorder = sal_True;
1843 0 : if ( pFrm->IsInSct() && pFrm->GetUpper()->IsColBodyFrm() )
1844 : {
1845 0 : const SwSectionFrm* pSct = pFrm->FindSctFrm();
1846 0 : bCommonBorder = pSct->GetFmt()->GetBalancedColumns().GetValue();
1847 : }
1848 :
1849 : // #i46181#
1850 0 : nSecondCheck = ( 1 == nSecondCheck &&
1851 0 : pFrm == this &&
1852 0 : IsTxtFrm() &&
1853 0 : bCommonBorder &&
1854 0 : !static_cast<const SwTxtFrm*>(this)->IsEmpty() ) ?
1855 : nUpper :
1856 0 : 0;
1857 :
1858 : nUpper += bCommonBorder ?
1859 0 : rAttrs.GetBottomLine( *(pFrm) ) :
1860 0 : rAttrs.CalcBottomLine();
1861 :
1862 : }
1863 : else
1864 : {
1865 : // #i46181#
1866 0 : nSecondCheck = 0;
1867 :
1868 0 : if( pFrm->IsVertical() )
1869 0 : nUpper = pFrm->Frm().Width() - pFrm->Prt().Width();
1870 : else
1871 0 : nUpper = pFrm->Frm().Height() - pFrm->Prt().Height();
1872 : }
1873 :
1874 0 : nSpace -= nUpper;
1875 :
1876 0 : if ( nSpace < 0 )
1877 : {
1878 0 : bRet = sal_False;
1879 :
1880 : // #i46181#
1881 0 : if ( nSecondCheck > 0 )
1882 : {
1883 : // The following code is intended to solve a (rare) problem
1884 : // causing some frames not to move backward:
1885 : // SwTxtFrm::WouldFit() claims that the whole paragraph
1886 : // fits into the given space and subtracts the height of
1887 : // all lines from nSpace. nSpace - nUpper is not a valid
1888 : // indicator if the frame should be allowed to move backward.
1889 : // We do a second check with the original remaining space
1890 : // reduced by the required upper space:
1891 0 : nOldSpace -= nSecondCheck;
1892 0 : const bool bSecondRet = nOldSpace >= 0 && pFrm->WouldFit( nOldSpace, bOldSplit, false );
1893 0 : if ( bSecondRet && bOldSplit && nOldSpace >= 0 )
1894 : {
1895 0 : bRet = sal_True;
1896 0 : bSplit = true;
1897 : }
1898 : }
1899 : }
1900 : }
1901 :
1902 : // OD 2004-03-01 #106629# - also consider lower spacing in table cells
1903 0 : if ( bRet && IsInTab() &&
1904 0 : pNewUpper->GetFmt()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::ADD_PARA_SPACING_TO_TABLE_CELLS) )
1905 : {
1906 0 : nSpace -= rAttrs.GetULSpace().GetLower();
1907 0 : if ( nSpace < 0 )
1908 : {
1909 0 : bRet = sal_False;
1910 : }
1911 : }
1912 :
1913 0 : if ( bRet && !bSplit && pFrm->IsKeep( rAttrs.GetAttrSet() ) )
1914 : {
1915 0 : if( bTstMove )
1916 : {
1917 0 : while( pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->HasFollow() )
1918 : {
1919 0 : pFrm = ((SwTxtFrm*)pFrm)->GetFollow();
1920 : }
1921 : // OD 11.04.2003 #108824# - If last follow frame of <this> text
1922 : // frame isn't valid, a formatting of the next content frame
1923 : // doesn't makes sense. Thus, return sal_True.
1924 0 : if ( IsAnFollow( pFrm ) && !pFrm->IsValid() )
1925 : {
1926 : OSL_FAIL( "Only a warning for task 108824:/n<SwCntntFrm::_WouldFit(..) - follow not valid!" );
1927 0 : return sal_True;
1928 : }
1929 : }
1930 : SwFrm *pNxt;
1931 0 : if( 0 != (pNxt = pFrm->FindNext()) && pNxt->IsCntntFrm() &&
1932 0 : ( !pFtnFrm || ( pNxt->IsInFtn() &&
1933 0 : pNxt->FindFtnFrm()->GetAttr() == pFtnFrm->GetAttr() ) ) )
1934 : {
1935 : // TestFormat(?) does not like paragraph- or character anchored objects.
1936 :
1937 : // current solution for the test formatting doesn't work, if
1938 : // objects are present in the remaining area of the new upper
1939 0 : if ( bTstMove &&
1940 0 : ( pNxt->GetDrawObjs() || bObjsInNewUpper ) )
1941 : {
1942 0 : return sal_True;
1943 : }
1944 :
1945 0 : if ( !pNxt->IsValid() )
1946 0 : MakeNxt( pFrm, pNxt );
1947 :
1948 : // Little trick: if the next has a predecessor, then the paragraph
1949 : // spacing has been calculated already, and we don't need to re-calculate
1950 : // it in an expensive way.
1951 0 : if( lcl_NotHiddenPrev( pNxt ) )
1952 0 : pTmpPrev = 0;
1953 : else
1954 : {
1955 0 : if( pFrm->IsTxtFrm() && ((SwTxtFrm*)pFrm)->IsHiddenNow() )
1956 0 : pTmpPrev = lcl_NotHiddenPrev( pFrm );
1957 : else
1958 0 : pTmpPrev = pFrm;
1959 : }
1960 0 : pFrm = (SwCntntFrm*)pNxt;
1961 : }
1962 : else
1963 0 : pFrm = 0;
1964 : }
1965 : else
1966 0 : pFrm = 0;
1967 :
1968 0 : } while ( bRet && pFrm );
1969 :
1970 0 : return bRet;
1971 : }
1972 :
1973 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|