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