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