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