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 :
21 : #include <hintids.hxx>
22 : #include <editeng/keepitem.hxx>
23 : #include <editeng/hyznitem.hxx>
24 : #include <pagefrm.hxx> // ChangeFtnRef
25 : #include <ndtxt.hxx> // MakeFrm()
26 : #include <dcontact.hxx> // SwDrawContact
27 : #include <dflyobj.hxx> // SwVirtFlyDrawObj
28 : #include <flyfrm.hxx>
29 : #include <ftnfrm.hxx> // SwFtnFrm
30 : #include <txtftn.hxx>
31 : #include <fmtftn.hxx>
32 : #include <paratr.hxx>
33 : #include <viewopt.hxx> // SwViewOptions
34 : #include <viewsh.hxx> // ViewShell
35 : #include <frmatr.hxx>
36 : #include <pam.hxx>
37 : #include <flyfrms.hxx>
38 : #include <fmtanchr.hxx>
39 : #include <itrform2.hxx> // SwTxtFormatter
40 : #include <widorp.hxx> // Widows and Orphans
41 : #include <txtcache.hxx>
42 : #include <porrst.hxx> // SwEmptyPortion
43 : #include <blink.hxx> // pBlink
44 : #include <porfld.hxx> // SwFldPortion
45 : #include <sectfrm.hxx> // SwSectionFrm
46 : #include <pormulti.hxx> // SwMultiPortion
47 :
48 : #include <rootfrm.hxx>
49 : #include <frmfmt.hxx> // SwFrmFmt
50 : // OD 2004-05-24 #i28701#
51 : #include <sortedobjs.hxx>
52 :
53 : // Tolerance in formatting and text output
54 : #define SLOPPY_TWIPS 5
55 :
56 : class FormatLevel
57 : {
58 : static MSHORT nLevel;
59 : public:
60 784 : inline FormatLevel() { ++nLevel; }
61 784 : inline ~FormatLevel() { --nLevel; }
62 784 : inline MSHORT GetLevel() const { return nLevel; }
63 0 : static bool LastLevel() { return 10 < nLevel; }
64 : };
65 : MSHORT FormatLevel::nLevel = 0;
66 :
67 5 : void ValidateTxt( SwFrm *pFrm ) // Friend of frame
68 : {
69 10 : if ( ( ! pFrm->IsVertical() &&
70 5 : pFrm->Frm().Width() == pFrm->GetUpper()->Prt().Width() ) ||
71 0 : ( pFrm->IsVertical() &&
72 0 : pFrm->Frm().Height() == pFrm->GetUpper()->Prt().Height() ) )
73 5 : pFrm->bValidSize = sal_True;
74 5 : }
75 :
76 5 : void SwTxtFrm::ValidateFrm()
77 : {
78 : // Validate surroundings to avoid oscillation
79 5 : SWAP_IF_SWAPPED( this )
80 :
81 5 : if ( !IsInFly() && !IsInTab() )
82 : { // Only validate 'this' when inside a fly, the rest should actually only be
83 : // needed for footnotes, which do not exist in flys.
84 5 : SwSectionFrm* pSct = FindSctFrm();
85 5 : if( pSct )
86 : {
87 0 : if( !pSct->IsColLocked() )
88 0 : pSct->ColLock();
89 : else
90 0 : pSct = NULL;
91 : }
92 :
93 5 : SwFrm *pUp = GetUpper();
94 5 : pUp->Calc();
95 5 : if( pSct )
96 0 : pSct->ColUnlock();
97 : }
98 5 : ValidateTxt( this );
99 :
100 : // We at least have to save the MustFit flag!
101 : OSL_ENSURE( HasPara(), "ResetPreps(), missing ParaPortion." );
102 5 : SwParaPortion *pPara = GetPara();
103 5 : const sal_Bool bMustFit = pPara->IsPrepMustFit();
104 5 : ResetPreps();
105 5 : pPara->SetPrepMustFit( bMustFit );
106 :
107 5 : UNDO_SWAP( this )
108 5 : }
109 :
110 : /*************************************************************************
111 : * ValidateBodyFrm()
112 : * After a RemoveFtn the BodyFrm and all Frms contained within it, need to be
113 : * recalculated, so that the DeadLine is right.
114 : * First we search outwards, on the way back we calculate everything.
115 : *************************************************************************/
116 :
117 5 : void _ValidateBodyFrm( SwFrm *pFrm )
118 : {
119 5 : if( pFrm && !pFrm->IsCellFrm() )
120 : {
121 5 : if( !pFrm->IsBodyFrm() && pFrm->GetUpper() )
122 0 : _ValidateBodyFrm( pFrm->GetUpper() );
123 5 : if( !pFrm->IsSctFrm() )
124 5 : pFrm->Calc();
125 : else
126 : {
127 0 : sal_Bool bOld = ((SwSectionFrm*)pFrm)->IsCntntLocked();
128 0 : ((SwSectionFrm*)pFrm)->SetCntntLock( sal_True );
129 0 : pFrm->Calc();
130 0 : if( !bOld )
131 0 : ((SwSectionFrm*)pFrm)->SetCntntLock( sal_False );
132 : }
133 : }
134 5 : }
135 :
136 5 : void SwTxtFrm::ValidateBodyFrm()
137 : {
138 5 : SWAP_IF_SWAPPED( this )
139 :
140 : // See comment in ValidateFrm()
141 15 : if ( !IsInFly() && !IsInTab() &&
142 5 : !( IsInSct() && FindSctFrm()->Lower()->IsColumnFrm() ) )
143 5 : _ValidateBodyFrm( GetUpper() );
144 :
145 5 : UNDO_SWAP( this )
146 5 : }
147 :
148 0 : sal_Bool SwTxtFrm::_GetDropRect( SwRect &rRect ) const
149 : {
150 0 : SWAP_IF_NOT_SWAPPED( this )
151 :
152 : OSL_ENSURE( HasPara(), "SwTxtFrm::_GetDropRect: try again next year." );
153 0 : SwTxtSizeInfo aInf( (SwTxtFrm*)this );
154 0 : SwTxtMargin aLine( (SwTxtFrm*)this, &aInf );
155 0 : if( aLine.GetDropLines() )
156 : {
157 0 : rRect.Top( aLine.Y() );
158 0 : rRect.Left( aLine.GetLineStart() );
159 0 : rRect.Height( aLine.GetDropHeight() );
160 0 : rRect.Width( aLine.GetDropLeft() );
161 :
162 0 : if ( IsRightToLeft() )
163 0 : SwitchLTRtoRTL( rRect );
164 :
165 0 : if ( IsVertical() )
166 0 : SwitchHorizontalToVertical( rRect );
167 0 : UNDO_SWAP( this )
168 0 : return sal_True;
169 : }
170 :
171 0 : UNDO_SWAP( this )
172 :
173 0 : return sal_False;
174 : }
175 :
176 664 : const SwBodyFrm *SwTxtFrm::FindBodyFrm() const
177 : {
178 664 : if ( IsInDocBody() )
179 : {
180 555 : const SwFrm *pFrm = GetUpper();
181 1646 : while( pFrm && !pFrm->IsBodyFrm() )
182 536 : pFrm = pFrm->GetUpper();
183 555 : return (const SwBodyFrm*)pFrm;
184 : }
185 109 : return 0;
186 : }
187 :
188 0 : sal_Bool SwTxtFrm::CalcFollow( const xub_StrLen nTxtOfst )
189 : {
190 0 : SWAP_IF_SWAPPED( this )
191 :
192 : OSL_ENSURE( HasFollow(), "CalcFollow: missing Follow." );
193 :
194 0 : SwTxtFrm* pMyFollow = GetFollow();
195 :
196 0 : SwParaPortion *pPara = GetPara();
197 0 : sal_Bool bFollowFld = pPara ? pPara->IsFollowField() : sal_False;
198 :
199 0 : if( !pMyFollow->GetOfst() || pMyFollow->GetOfst() != nTxtOfst ||
200 0 : bFollowFld || pMyFollow->IsFieldFollow() ||
201 0 : ( pMyFollow->IsVertical() && !pMyFollow->Prt().Width() ) ||
202 0 : ( ! pMyFollow->IsVertical() && !pMyFollow->Prt().Height() ) )
203 : {
204 : #if OSL_DEBUG_LEVEL > 0
205 : const SwFrm *pOldUp = GetUpper();
206 : #endif
207 :
208 0 : SWRECTFN ( this )
209 0 : SwTwips nOldBottom = (GetUpper()->Frm().*fnRect->fnGetBottom)();
210 0 : SwTwips nMyPos = (Frm().*fnRect->fnGetTop)();
211 :
212 0 : const SwPageFrm *pPage = 0;
213 0 : sal_Bool bOldInvaCntnt = sal_True;
214 0 : if ( !IsInFly() && GetNext() )
215 : {
216 0 : pPage = FindPageFrm();
217 : // Minimize = that is set back if needed - for invalidation see below
218 0 : bOldInvaCntnt = pPage->IsInvalidCntnt();
219 : }
220 :
221 0 : pMyFollow->_SetOfst( nTxtOfst );
222 0 : pMyFollow->SetFieldFollow( bFollowFld );
223 0 : if( HasFtn() || pMyFollow->HasFtn() )
224 : {
225 0 : ValidateFrm();
226 0 : ValidateBodyFrm();
227 0 : if( pPara )
228 : {
229 0 : *(pPara->GetReformat()) = SwCharRange();
230 0 : *(pPara->GetDelta()) = 0;
231 : }
232 : }
233 :
234 : // The footnote area must not get larger
235 0 : SwSaveFtnHeight aSave( FindFtnBossFrm( sal_True ), LONG_MAX );
236 :
237 0 : pMyFollow->CalcFtnFlag();
238 0 : if ( !pMyFollow->GetNext() && !pMyFollow->HasFtn() )
239 0 : nOldBottom = bVert ? 0 : LONG_MAX;
240 :
241 0 : while( true )
242 : {
243 0 : if( !FormatLevel::LastLevel() )
244 : {
245 : // If the follow is contained within a column section or column
246 : // frame, we need to calculate that first. This is because the
247 : // FormatWidthCols() does not work if it is called from MakeAll
248 : // of the _locked_ follow.
249 0 : SwSectionFrm* pSct = pMyFollow->FindSctFrm();
250 0 : if( pSct && !pSct->IsAnLower( this ) )
251 : {
252 0 : if( pSct->GetFollow() )
253 0 : pSct->SimpleFormat();
254 0 : else if( ( pSct->IsVertical() && !pSct->Frm().Width() ) ||
255 0 : ( ! pSct->IsVertical() && !pSct->Frm().Height() ) )
256 0 : break;
257 : }
258 : // OD 14.03.2003 #i11760# - intrinsic format of follow is controlled.
259 0 : if ( FollowFormatAllowed() )
260 : {
261 : // OD 14.03.2003 #i11760# - no nested format of follows, if
262 : // text frame is contained in a column frame.
263 : // Thus, forbid intrinsic format of follow.
264 : {
265 0 : bool bIsFollowInColumn = false;
266 0 : SwFrm* pFollowUpper = pMyFollow->GetUpper();
267 0 : while ( pFollowUpper )
268 : {
269 0 : if ( pFollowUpper->IsColumnFrm() )
270 : {
271 0 : bIsFollowInColumn = true;
272 0 : break;
273 : }
274 0 : if ( pFollowUpper->IsPageFrm() ||
275 0 : pFollowUpper->IsFlyFrm() )
276 : {
277 0 : break;
278 : }
279 0 : pFollowUpper = pFollowUpper->GetUpper();
280 : }
281 0 : if ( bIsFollowInColumn )
282 : {
283 0 : pMyFollow->ForbidFollowFormat();
284 : }
285 : }
286 :
287 0 : pMyFollow->Calc();
288 : // The Follow can tell from its Frm().Height() that something went wrong
289 : OSL_ENSURE( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: cheesy follow" );
290 0 : if( pMyFollow->GetPrev() )
291 : {
292 0 : pMyFollow->Prepare( PREP_CLEAR );
293 0 : pMyFollow->Calc();
294 : OSL_ENSURE( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: very cheesy follow" );
295 : }
296 :
297 : // OD 14.03.2003 #i11760# - reset control flag for follow format.
298 0 : pMyFollow->AllowFollowFormat();
299 : }
300 :
301 : // Make sure that the Follow gets painted
302 0 : pMyFollow->SetCompletePaint();
303 : }
304 :
305 0 : pPara = GetPara();
306 : // As long as the Follow is requested due to orphan lines, it is passed these
307 : // and is reformatted if possible
308 0 : if( pPara && pPara->IsPrepWidows() )
309 0 : CalcPreps();
310 : else
311 0 : break;
312 : }
313 :
314 0 : if( HasFtn() || pMyFollow->HasFtn() )
315 : {
316 0 : ValidateBodyFrm();
317 0 : ValidateFrm();
318 0 : if( pPara )
319 : {
320 0 : *(pPara->GetReformat()) = SwCharRange();
321 0 : *(pPara->GetDelta()) = 0;
322 : }
323 : }
324 :
325 0 : if ( pPage )
326 : {
327 0 : if ( !bOldInvaCntnt )
328 0 : pPage->ValidateCntnt();
329 : }
330 :
331 : #if OSL_DEBUG_LEVEL > 0
332 : OSL_ENSURE( pOldUp == GetUpper(), "SwTxtFrm::CalcFollow: heavy follow" );
333 : #endif
334 :
335 : const long nRemaining =
336 0 : - (GetUpper()->Frm().*fnRect->fnBottomDist)( nOldBottom );
337 0 : if ( nRemaining > 0 && !GetUpper()->IsSctFrm() &&
338 : nRemaining != ( bVert ?
339 0 : nMyPos - Frm().Right() :
340 0 : Frm().Top() - nMyPos ) )
341 : {
342 0 : UNDO_SWAP( this )
343 0 : return sal_True;
344 0 : }
345 : }
346 :
347 0 : UNDO_SWAP( this )
348 :
349 0 : return sal_False;
350 : }
351 :
352 982 : void SwTxtFrm::AdjustFrm( const SwTwips nChgHght, sal_Bool bHasToFit )
353 : {
354 982 : if( IsUndersized() )
355 : {
356 27 : if( GetOfst() && !IsFollow() ) // A scrolled paragraph (undersized)
357 0 : return;
358 27 : SetUndersized( nChgHght == 0 || bHasToFit );
359 : }
360 :
361 : // AdjustFrm is called with a swapped frame during
362 : // formatting but the frame is not swapped during FormatEmpty
363 982 : SWAP_IF_SWAPPED( this )
364 982 : SWRECTFN ( this )
365 :
366 : // The Frame's size variable is incremented by Grow or decremented by Shrink.
367 : // If the size cannot change, nothing should happen!
368 982 : if( nChgHght >= 0)
369 : {
370 982 : SwTwips nChgHeight = nChgHght;
371 982 : if( nChgHght && !bHasToFit )
372 : {
373 875 : if( IsInFtn() && !IsInSct() )
374 : {
375 5 : SwTwips nReal = Grow( nChgHght, sal_True );
376 5 : if( nReal < nChgHght )
377 : {
378 0 : SwTwips nBot = (*fnRect->fnYInc)( (Frm().*fnRect->fnGetBottom)(),
379 0 : nChgHght - nReal );
380 0 : SwFrm* pCont = FindFtnFrm()->GetUpper();
381 :
382 0 : if( (pCont->Frm().*fnRect->fnBottomDist)( nBot ) > 0 )
383 : {
384 0 : (Frm().*fnRect->fnAddBottom)( nChgHght );
385 0 : if( bVert )
386 0 : Prt().SSize().Width() += nChgHght;
387 : else
388 0 : Prt().SSize().Height() += nChgHght;
389 0 : UNDO_SWAP( this )
390 0 : return;
391 : }
392 : }
393 : }
394 :
395 875 : Grow( nChgHght );
396 :
397 875 : if ( IsInFly() )
398 : {
399 : // If one of the Upper is a Fly, it's very likely that this fly changes its
400 : // position by the Grow. Therefore, my position has to be corrected also or
401 : // the check further down is not meaningful.
402 : // The predecessors need to be calculated, so that the position can be
403 : // calculated correctly.
404 29 : if ( GetPrev() )
405 : {
406 7 : SwFrm *pPre = GetUpper()->Lower();
407 10 : do
408 10 : { pPre->Calc();
409 10 : pPre = pPre->GetNext();
410 : } while ( pPre && pPre != this );
411 : }
412 29 : const Point aOldPos( Frm().Pos() );
413 29 : MakePos();
414 29 : if ( aOldPos != Frm().Pos() )
415 : {
416 : // OD 2004-07-01 #i28701# - use new method <SwFrm::InvalidateObjs(..)>
417 : // No format is performed for the floating screen objects.
418 0 : InvalidateObjs( true );
419 : }
420 : }
421 875 : nChgHeight = 0;
422 : }
423 : // A Grow() is always accepted by the Layout, even if the
424 : // FixSize of the surrounding layout frame should not allow it.
425 : // We text for this case and correct the values.
426 : // The Frm must NOT be shrinked further than its size permits
427 : // even in the case of an emergency.
428 : SwTwips nRstHeight;
429 982 : if ( IsVertical() )
430 : {
431 : OSL_ENSURE( ! IsSwapped(),"Swapped frame while calculating nRstHeight" );
432 :
433 : //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
434 0 : if ( IsVertLR() )
435 0 : nRstHeight = GetUpper()->Frm().Left()
436 0 : + GetUpper()->Prt().Left()
437 0 : + GetUpper()->Prt().Width()
438 0 : - Frm().Left();
439 : else
440 0 : nRstHeight = Frm().Left() + Frm().Width() -
441 0 : ( GetUpper()->Frm().Left() + GetUpper()->Prt().Left() );
442 : }
443 : else
444 982 : nRstHeight = GetUpper()->Frm().Top()
445 982 : + GetUpper()->Prt().Top()
446 982 : + GetUpper()->Prt().Height()
447 1964 : - Frm().Top();
448 :
449 : // We can get a bit of space in table cells, because there could be some
450 : // left through a vertical alignment to the top.
451 : // #115759# - assure, that first lower in upper
452 : // is the current one or is valid.
453 1324 : if ( IsInTab() &&
454 341 : ( GetUpper()->Lower() == this ||
455 1 : GetUpper()->Lower()->IsValid() ) )
456 : {
457 682 : long nAdd = (*fnRect->fnYDiff)( (GetUpper()->Lower()->Frm().*fnRect->fnGetTop)(),
458 1023 : (GetUpper()->*fnRect->fnGetPrtTop)() );
459 : OSL_ENSURE( nAdd >= 0, "Ey" );
460 341 : nRstHeight += nAdd;
461 : }
462 :
463 : /* ------------------------------------
464 : * nRstHeight < 0 means that the TxtFrm is located completely outside of its Upper.
465 : * This can happen, if it's located within a FlyAtCntFrm, which changed sides by a
466 : * Grow(). In such a case, it's wrong to execute the following Grow().
467 : * In the case of a bug, we end up with an infinite loop.
468 : * -----------------------------------*/
469 982 : SwTwips nFrmHeight = (Frm().*fnRect->fnGetHeight)();
470 982 : SwTwips nPrtHeight = (Prt().*fnRect->fnGetHeight)();
471 :
472 982 : if( nRstHeight < nFrmHeight )
473 : {
474 : // It can be that I have the right size, but the Upper is too small and can get me some room
475 29 : if( ( nRstHeight >= 0 || ( IsInFtn() && IsInSct() ) ) && !bHasToFit )
476 29 : nRstHeight += GetUpper()->Grow( nFrmHeight - nRstHeight );
477 : // In column sections we do not want to get too big or else more areas are created by
478 : // GetNextSctLeaf. Instead, we shrink and remember bUndersized, so that FormatWidthCols
479 : // can calculate the right column size.
480 29 : if ( nRstHeight < nFrmHeight )
481 : {
482 31 : if( bHasToFit || !IsMoveable() ||
483 2 : ( IsInSct() && !FindSctFrm()->MoveAllowed(this) ) )
484 : {
485 28 : SetUndersized( sal_True );
486 28 : Shrink( Min( ( nFrmHeight - nRstHeight), nPrtHeight ) );
487 : }
488 : else
489 1 : SetUndersized( sal_False );
490 : }
491 : }
492 953 : else if( nChgHeight )
493 : {
494 0 : if( nRstHeight - nFrmHeight < nChgHeight )
495 0 : nChgHeight = nRstHeight - nFrmHeight;
496 0 : if( nChgHeight )
497 0 : Grow( nChgHeight );
498 : }
499 : }
500 : else
501 0 : Shrink( -nChgHght );
502 :
503 982 : UNDO_SWAP( this )
504 : }
505 :
506 : /*************************************************************************
507 : * SwTxtFrm::AdjustFollow()
508 : * AdjustFollow expects the following situation:
509 : * The SwTxtIter points to the lower end of the Master, the Offset is set in
510 : * the Follow.
511 : * nOffset holds the Offset in the text string, from which the Master closes
512 : * and the Follow starts.
513 : * If it's 0, the FollowFrame is deleted.
514 : *************************************************************************/
515 :
516 10 : void SwTxtFrm::_AdjustFollow( SwTxtFormatter &rLine,
517 : const xub_StrLen nOffset, const xub_StrLen nEnd,
518 : const sal_uInt8 nMode )
519 : {
520 10 : SwFrmSwapper aSwapper( this, sal_False );
521 :
522 : // We got the rest of the text mass: Delete all Follows
523 : // DummyPortions() are a special case.
524 : // Special cases are controlled by parameter <nMode>.
525 10 : if( HasFollow() && !(nMode & 1) && nOffset == nEnd )
526 : {
527 0 : while( GetFollow() )
528 : {
529 0 : if( ((SwTxtFrm*)GetFollow())->IsLocked() )
530 : {
531 : OSL_FAIL( "+SwTxtFrm::JoinFrm: Follow is locked." );
532 : return;
533 : }
534 0 : JoinFrm();
535 : }
536 :
537 : return;
538 : }
539 :
540 : // Dancing on the volcano: We'll just format the last line quickly
541 : // for the QuoVadis stuff.
542 : // The Offset can move of course:
543 20 : const xub_StrLen nNewOfst = ( IsInFtn() && ( !GetIndNext() || HasFollow() ) ) ?
544 20 : rLine.FormatQuoVadis(nOffset) : nOffset;
545 :
546 10 : if( !(nMode & 1) )
547 : {
548 : // We steal text mass from our Follows
549 : // It can happen that we have to join some of them
550 20 : while( GetFollow() && GetFollow()->GetFollow() &&
551 0 : nNewOfst >= GetFollow()->GetFollow()->GetOfst() )
552 : {
553 0 : JoinFrm();
554 : }
555 : }
556 :
557 : // The Offset moved
558 10 : if( GetFollow() )
559 : {
560 : #if OSL_DEBUG_LEVEL > 1
561 : static bool bTest = false;
562 : if( !bTest || ( nMode & 1 ) )
563 : #endif
564 0 : if ( nMode )
565 0 : GetFollow()->ManipOfst( 0 );
566 :
567 0 : if ( CalcFollow( nNewOfst ) ) // CalcFollow only at the end, we do a SetOfst there
568 0 : rLine.SetOnceMore( sal_True );
569 10 : }
570 : }
571 :
572 0 : SwCntntFrm *SwTxtFrm::JoinFrm()
573 : {
574 : OSL_ENSURE( GetFollow(), "+SwTxtFrm::JoinFrm: no follow" );
575 0 : SwTxtFrm *pFoll = GetFollow();
576 :
577 0 : SwTxtFrm *pNxt = pFoll->GetFollow();
578 :
579 : // All footnotes of the to-be-destroyed Follow are relocated to us
580 0 : xub_StrLen nStart = pFoll->GetOfst();
581 0 : if ( pFoll->HasFtn() )
582 : {
583 0 : const SwpHints *pHints = pFoll->GetTxtNode()->GetpSwpHints();
584 0 : if( pHints )
585 : {
586 0 : SwFtnBossFrm *pFtnBoss = 0;
587 0 : SwFtnBossFrm *pEndBoss = 0;
588 0 : for ( sal_uInt16 i = 0; i < pHints->Count(); ++i )
589 : {
590 0 : const SwTxtAttr *pHt = (*pHints)[i];
591 0 : if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nStart )
592 : {
593 0 : if( pHt->GetFtn().IsEndNote() )
594 : {
595 0 : if( !pEndBoss )
596 0 : pEndBoss = pFoll->FindFtnBossFrm();
597 0 : pEndBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this );
598 : }
599 : else
600 : {
601 0 : if( !pFtnBoss )
602 0 : pFtnBoss = pFoll->FindFtnBossFrm( sal_True );
603 0 : pFtnBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this );
604 : }
605 0 : SetFtn( sal_True );
606 : }
607 : }
608 : }
609 : }
610 :
611 : #ifdef DBG_UTIL
612 : else if ( pFoll->GetValidPrtAreaFlag() ||
613 : pFoll->GetValidSizeFlag() )
614 : {
615 : pFoll->CalcFtnFlag();
616 : OSL_ENSURE( !pFoll->HasFtn(), "Missing FtnFlag." );
617 : }
618 : #endif
619 :
620 0 : pFoll->MoveFlyInCnt( this, nStart, STRING_LEN );
621 0 : pFoll->SetFtn( sal_False );
622 : // #i27138#
623 : // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation.
624 : // Relation CONTENT_FLOWS_FROM for current next paragraph will change
625 : // and relation CONTENT_FLOWS_TO for current previous paragraph, which
626 : // is <this>, will change.
627 : {
628 0 : ViewShell* pViewShell( pFoll->getRootFrm()->GetCurrShell() );
629 0 : if ( pViewShell && pViewShell->GetLayout() &&
630 0 : pViewShell->GetLayout()->IsAnyShellAccessible() )
631 : {
632 : pViewShell->InvalidateAccessibleParaFlowRelation(
633 0 : dynamic_cast<SwTxtFrm*>(pFoll->FindNextCnt( true )),
634 0 : this );
635 : }
636 : }
637 0 : pFoll->Cut();
638 0 : SetFollow(pNxt);
639 0 : delete pFoll;
640 0 : return pNxt;
641 : }
642 :
643 0 : SwCntntFrm *SwTxtFrm::SplitFrm( const xub_StrLen nTxtPos )
644 : {
645 0 : SWAP_IF_SWAPPED( this )
646 :
647 : // The Paste sends a Modify() to me
648 : // I lock myself, so that my data does not disappear
649 0 : SwTxtFrmLocker aLock( this );
650 0 : SwTxtFrm *pNew = (SwTxtFrm *)(GetTxtNode()->MakeFrm( this ));
651 :
652 0 : pNew->SetFollow( GetFollow() );
653 0 : SetFollow( pNew );
654 :
655 0 : pNew->Paste( GetUpper(), GetNext() );
656 : // #i27138#
657 : // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation.
658 : // Relation CONTENT_FLOWS_FROM for current next paragraph will change
659 : // and relation CONTENT_FLOWS_TO for current previous paragraph, which
660 : // is <this>, will change.
661 : {
662 0 : ViewShell* pViewShell( pNew->getRootFrm()->GetCurrShell() );
663 0 : if ( pViewShell && pViewShell->GetLayout() &&
664 0 : pViewShell->GetLayout()->IsAnyShellAccessible() )
665 : {
666 : pViewShell->InvalidateAccessibleParaFlowRelation(
667 0 : dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )),
668 0 : this );
669 : }
670 : }
671 :
672 : // If footnotes end up in pNew bz our actions, we need
673 : // to re-register them
674 0 : if ( HasFtn() )
675 : {
676 0 : const SwpHints *pHints = GetTxtNode()->GetpSwpHints();
677 0 : if( pHints )
678 : {
679 0 : SwFtnBossFrm *pFtnBoss = 0;
680 0 : SwFtnBossFrm *pEndBoss = 0;
681 0 : for ( sal_uInt16 i = 0; i < pHints->Count(); ++i )
682 : {
683 0 : const SwTxtAttr *pHt = (*pHints)[i];
684 0 : if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nTxtPos )
685 : {
686 0 : if( pHt->GetFtn().IsEndNote() )
687 : {
688 0 : if( !pEndBoss )
689 0 : pEndBoss = FindFtnBossFrm();
690 0 : pEndBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew );
691 : }
692 : else
693 : {
694 0 : if( !pFtnBoss )
695 0 : pFtnBoss = FindFtnBossFrm( sal_True );
696 0 : pFtnBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew );
697 : }
698 0 : pNew->SetFtn( sal_True );
699 : }
700 : }
701 : }
702 : }
703 :
704 : #ifdef DBG_UTIL
705 : else
706 : {
707 : CalcFtnFlag( nTxtPos-1 );
708 : OSL_ENSURE( !HasFtn(), "Missing FtnFlag." );
709 : }
710 : #endif
711 :
712 0 : MoveFlyInCnt( pNew, nTxtPos, STRING_LEN );
713 :
714 : // No SetOfst or CalcFollow, because an AdjustFollow follows immediately anyways
715 :
716 0 : pNew->ManipOfst( nTxtPos );
717 :
718 0 : UNDO_SWAP( this )
719 0 : return pNew;
720 : }
721 :
722 0 : void SwTxtFrm::_SetOfst( const xub_StrLen nNewOfst )
723 : {
724 : // We do not need to invalidate out Follow.
725 : // We are a Follow, get formatted right away and call
726 : // SetOfst() from there
727 0 : nOfst = nNewOfst;
728 0 : SwParaPortion *pPara = GetPara();
729 0 : if( pPara )
730 : {
731 0 : SwCharRange &rReformat = *(pPara->GetReformat());
732 0 : rReformat.Start() = 0;
733 0 : rReformat.Len() = GetTxt().Len();
734 0 : *(pPara->GetDelta()) = rReformat.Len();
735 : }
736 0 : InvalidateSize();
737 0 : }
738 :
739 784 : sal_Bool SwTxtFrm::CalcPreps()
740 : {
741 : OSL_ENSURE( ! IsVertical() || ! IsSwapped(), "SwTxtFrm::CalcPreps with swapped frame" );
742 784 : SWRECTFN( this );
743 :
744 784 : SwParaPortion *pPara = GetPara();
745 784 : if ( !pPara )
746 631 : return sal_False;
747 153 : sal_Bool bPrep = pPara->IsPrep();
748 153 : sal_Bool bPrepWidows = pPara->IsPrepWidows();
749 153 : sal_Bool bPrepAdjust = pPara->IsPrepAdjust();
750 153 : sal_Bool bPrepMustFit = pPara->IsPrepMustFit();
751 153 : ResetPreps();
752 :
753 153 : sal_Bool bRet = sal_False;
754 153 : if( bPrep && !pPara->GetReformat()->Len() )
755 : {
756 : // PREP_WIDOWS means that the orphans rule got activated in the Follow.
757 : // In unfortunate cases we could also have a PrepAdjust!
758 19 : if( bPrepWidows )
759 : {
760 0 : if( !GetFollow() )
761 : {
762 : OSL_ENSURE( GetFollow(), "+SwTxtFrm::CalcPreps: no credits" );
763 0 : return sal_False;
764 : }
765 :
766 : // We need to prepare for two cases:
767 : // We were able to hand over a few lines to the Follow
768 : // -> we need to shrink
769 : // or we need to go on the next page
770 : // -> we let our Frame become too big
771 :
772 0 : SwTwips nChgHeight = GetParHeight();
773 0 : if( nChgHeight >= (Prt().*fnRect->fnGetHeight)() )
774 : {
775 0 : if( bPrepMustFit )
776 : {
777 0 : GetFollow()->SetJustWidow( sal_True );
778 0 : GetFollow()->Prepare( PREP_CLEAR );
779 : }
780 0 : else if ( bVert )
781 : {
782 0 : Frm().Width( Frm().Width() + Frm().Left() );
783 0 : Prt().Width( Prt().Width() + Frm().Left() );
784 0 : Frm().Left( 0 );
785 0 : SetWidow( sal_True );
786 : }
787 : else
788 : {
789 0 : SwTwips nTmp = LONG_MAX - (Frm().Top()+10000);
790 0 : SwTwips nDiff = nTmp - Frm().Height();
791 0 : Frm().Height( nTmp );
792 0 : Prt().Height( Prt().Height() + nDiff );
793 0 : SetWidow( sal_True );
794 : }
795 : }
796 : else
797 : {
798 : OSL_ENSURE( nChgHeight < (Prt().*fnRect->fnGetHeight)(),
799 : "+SwTxtFrm::CalcPrep: wanna shrink" );
800 :
801 0 : nChgHeight = (Prt().*fnRect->fnGetHeight)() - nChgHeight;
802 :
803 0 : GetFollow()->SetJustWidow( sal_True );
804 0 : GetFollow()->Prepare( PREP_CLEAR );
805 0 : Shrink( nChgHeight );
806 0 : SwRect &rRepaint = *(pPara->GetRepaint());
807 :
808 0 : if ( bVert )
809 : {
810 0 : SwRect aRepaint( Frm().Pos() + Prt().Pos(), Prt().SSize() );
811 0 : SwitchVerticalToHorizontal( aRepaint );
812 0 : rRepaint.Chg( aRepaint.Pos(), aRepaint.SSize() );
813 : }
814 : else
815 0 : rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() );
816 :
817 0 : if( 0 >= rRepaint.Width() )
818 0 : rRepaint.Width(1);
819 : }
820 0 : bRet = sal_True;
821 : }
822 :
823 19 : else if ( bPrepAdjust )
824 : {
825 19 : if ( HasFtn() )
826 : {
827 0 : if( !CalcPrepFtnAdjust() )
828 : {
829 0 : if( bPrepMustFit )
830 : {
831 0 : SwTxtLineAccess aAccess( this );
832 0 : aAccess.GetPara()->SetPrepMustFit( sal_True );
833 : }
834 0 : return sal_False;
835 : }
836 : }
837 :
838 19 : SWAP_IF_NOT_SWAPPED( this )
839 :
840 19 : SwTxtFormatInfo aInf( this );
841 19 : SwTxtFormatter aLine( this, &aInf );
842 :
843 19 : WidowsAndOrphans aFrmBreak( this );
844 : // Whatever the attributes say: we split the paragraph in
845 : // MustFit in any case
846 19 : if( bPrepMustFit )
847 : {
848 0 : aFrmBreak.SetKeep( sal_False );
849 0 : aFrmBreak.ClrOrphLines();
850 : }
851 : // Before calling FormatAdjust, we need to make sure
852 : // that the lines protruding at the bottom get indeed
853 : // truncated
854 19 : sal_Bool bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine );
855 19 : bRet = sal_True;
856 42 : while( !bBreak && aLine.Next() )
857 : {
858 4 : bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine );
859 : }
860 19 : if( bBreak )
861 : {
862 : // We run into troubles: when TruncLines get called, the
863 : // conditions in IsInside change immediately such that
864 : // IsBreakNow can return different results.
865 : // For this reason, we make it clear to rFrmBreak, that the
866 : // end is reached at the location of rLine.
867 : // Let's see if it works ...
868 0 : aLine.TruncLines();
869 0 : aFrmBreak.SetRstHeight( aLine );
870 0 : FormatAdjust( aLine, aFrmBreak, aInf.GetTxt().Len(), aInf.IsStop() );
871 : }
872 : else
873 : {
874 19 : if( !GetFollow() )
875 : {
876 : FormatAdjust( aLine, aFrmBreak,
877 19 : aInf.GetTxt().Len(), aInf.IsStop() );
878 : }
879 0 : else if ( !aFrmBreak.IsKeepAlways() )
880 : {
881 : // We delete a line before the Master, because the Follow
882 : // could hand over a line
883 0 : const SwCharRange aFollowRg( GetFollow()->GetOfst(), 1 );
884 0 : *(pPara->GetReformat()) += aFollowRg;
885 : // We should continue!
886 0 : bRet = sal_False;
887 : }
888 : }
889 :
890 19 : UNDO_SWAP( this )
891 : // A final check, if FormatAdjust() didn't help we need to
892 : // truncate
893 19 : if( bPrepMustFit )
894 : {
895 0 : const SwTwips nMust = (GetUpper()->*fnRect->fnGetPrtBottom)();
896 0 : const SwTwips nIs = (Frm().*fnRect->fnGetBottom)();
897 :
898 0 : if( bVert && nIs < nMust )
899 : {
900 0 : Shrink( nMust - nIs );
901 0 : if( Prt().Width() < 0 )
902 0 : Prt().Width( 0 );
903 0 : SetUndersized( sal_True );
904 : }
905 0 : else if ( ! bVert && nIs > nMust )
906 : {
907 0 : Shrink( nIs - nMust );
908 0 : if( Prt().Height() < 0 )
909 0 : Prt().Height( 0 );
910 0 : SetUndersized( sal_True );
911 : }
912 19 : }
913 : }
914 : }
915 153 : pPara->SetPrepMustFit( bPrepMustFit );
916 153 : return bRet;
917 : }
918 :
919 : /*************************************************************************
920 : * SwTxtFrm::FormatAdjust()
921 : * We rewire the footnotes and the character bound objects
922 : *************************************************************************/
923 :
924 : #define CHG_OFFSET( pFrm, nNew )\
925 : {\
926 : if( pFrm->GetOfst() < nNew )\
927 : pFrm->MoveFlyInCnt( this, 0, nNew );\
928 : else if( pFrm->GetOfst() > nNew )\
929 : MoveFlyInCnt( pFrm, nNew, STRING_LEN );\
930 : }
931 :
932 662 : void SwTxtFrm::FormatAdjust( SwTxtFormatter &rLine,
933 : WidowsAndOrphans &rFrmBreak,
934 : const xub_StrLen nStrLen,
935 : const sal_Bool bDummy )
936 : {
937 662 : SWAP_IF_NOT_SWAPPED( this )
938 :
939 662 : SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
940 :
941 662 : xub_StrLen nEnd = rLine.GetStart();
942 :
943 662 : sal_Bool bHasToFit = pPara->IsPrepMustFit();
944 :
945 : // The StopFlag is set by footnotes which want to go onto the next page
946 : // Call base class method <SwTxtFrmBreak::IsBreakNow(..)>
947 : // instead of method <WidowsAndOrphans::IsBreakNow(..)> to get a break,
948 : // even if due to widow rule no enough lines exists.
949 662 : sal_uInt8 nNew = ( !GetFollow() &&
950 : nEnd < nStrLen &&
951 584 : ( rLine.IsStop() ||
952 : ( bHasToFit
953 0 : ? ( rLine.GetLineNr() > 1 &&
954 0 : !rFrmBreak.IsInside( rLine ) )
955 584 : : rFrmBreak.IsBreakNow( rLine ) ) ) )
956 1246 : ? 1 : 0;
957 : // --> OD #i84870#
958 : // no split of text frame, which only contains a as-character anchored object
959 : const bool bOnlyContainsAsCharAnchoredObj =
960 662 : !IsFollow() && nStrLen == 1 &&
961 252 : GetDrawObjs() && GetDrawObjs()->Count() == 1 &&
962 914 : (*GetDrawObjs())[0]->GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AS_CHAR;
963 662 : if ( nNew && bOnlyContainsAsCharAnchoredObj )
964 : {
965 0 : nNew = 0;
966 : }
967 : // <--
968 662 : if ( nNew )
969 : {
970 0 : SplitFrm( nEnd );
971 : }
972 :
973 662 : const SwFrm *pBodyFrm = (const SwFrm*)(FindBodyFrm());
974 :
975 553 : const long nBodyHeight = pBodyFrm ? ( IsVertical() ?
976 0 : pBodyFrm->Frm().Width() :
977 1215 : pBodyFrm->Frm().Height() ) : 0;
978 :
979 : // If the current values have been calculated, show that they
980 : // are valid now
981 662 : *(pPara->GetReformat()) = SwCharRange();
982 662 : bool bDelta = *pPara->GetDelta() != 0;
983 662 : *(pPara->GetDelta()) = 0;
984 :
985 662 : if( rLine.IsStop() )
986 : {
987 0 : rLine.TruncLines( true );
988 0 : nNew = 1;
989 : }
990 :
991 : // FindBreak truncates the last line
992 662 : if( !rFrmBreak.FindBreak( this, rLine, bHasToFit ) )
993 : {
994 : // If we're done formatting, we set nEnd to the end.
995 : // AdjustFollow might execute JoinFrm() because of this.
996 : // Else, nEnd is the end of the last line in the Master.
997 662 : xub_StrLen nOld = nEnd;
998 662 : nEnd = rLine.GetEnd();
999 662 : if( GetFollow() )
1000 : {
1001 0 : if( nNew && nOld < nEnd )
1002 0 : RemoveFtn( nOld, nEnd - nOld );
1003 0 : CHG_OFFSET( GetFollow(), nEnd )
1004 0 : if( !bDelta )
1005 0 : GetFollow()->ManipOfst( nEnd );
1006 : }
1007 : }
1008 : else
1009 : { // If we pass over lines, we must not call Join in Follows, instead we even
1010 : // need to create a Follow.
1011 : // We also need to do this if the whole mass of text remains in the Master,
1012 : // because a hard line break could necessitate another line (without text mass)!
1013 0 : nEnd = rLine.GetEnd();
1014 0 : if( GetFollow() )
1015 : {
1016 : // Another case for not joining the follow:
1017 : // Text frame has no content, but a numbering. Then, do *not* join.
1018 : // Example of this case: When an empty, but numbered paragraph
1019 : // at the end of page is completely displaced by a fly frame.
1020 : // Thus, the text frame introduced a follow by a
1021 : // <SwTxtFrm::SplitFrm(..)> - see below. The follow then shows
1022 : // the numbering and must stay.
1023 0 : if ( GetFollow()->GetOfst() != nEnd ||
1024 0 : GetFollow()->IsFieldFollow() ||
1025 0 : ( nStrLen == 0 && GetTxtNode()->GetNumRule() ) )
1026 : {
1027 0 : nNew |= 3;
1028 : }
1029 0 : CHG_OFFSET( GetFollow(), nEnd )
1030 0 : GetFollow()->ManipOfst( nEnd );
1031 : }
1032 : else
1033 : {
1034 : // Only split frame, if the frame contains
1035 : // content or contains no content, but has a numbering.
1036 : // OD #i84870# - no split, if text frame only contains one
1037 : // as-character anchored object.
1038 0 : if ( !bOnlyContainsAsCharAnchoredObj &&
1039 : ( nStrLen > 0 ||
1040 0 : ( nStrLen == 0 && GetTxtNode()->GetNumRule() ) )
1041 : )
1042 : {
1043 0 : SplitFrm( nEnd );
1044 0 : nNew |= 3;
1045 : }
1046 : }
1047 : // If the remaining height changed e.g by RemoveFtn() we need to
1048 : // fill up in order to avoid oscillation.
1049 0 : if( bDummy && pBodyFrm &&
1050 0 : nBodyHeight < ( IsVertical() ?
1051 0 : pBodyFrm->Frm().Width() :
1052 0 : pBodyFrm->Frm().Height() ) )
1053 0 : rLine.MakeDummyLine();
1054 : }
1055 :
1056 : // In AdjustFrm() we set ourselves via Grow/Shrink
1057 : // In AdjustFollow() we set our FollowFrame
1058 :
1059 662 : const SwTwips nDocPrtTop = Frm().Top() + Prt().Top();
1060 662 : const SwTwips nOldHeight = Prt().SSize().Height();
1061 662 : SwTwips nChg = rLine.CalcBottomLine() - nDocPrtTop - nOldHeight;
1062 : // --> OD #i84870# - no shrink of text frame, if it only contains one
1063 : // as-character anchored object.
1064 662 : if ( nChg < 0 &&
1065 : bOnlyContainsAsCharAnchoredObj )
1066 : {
1067 0 : nChg = 0;
1068 : }
1069 : // <--
1070 :
1071 : // Vertical Formatting:
1072 : // The (rotated) repaint rectangle's x coordinate referes to the frame.
1073 : // If the frame grows (or shirks) the repaint rectangle cannot simply
1074 : // be rotated back after formatting, because we use the upper left point
1075 : // of the frame for rotation. This point changes when growing/shrinking.
1076 :
1077 : //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
1078 662 : if ( IsVertical() && !IsVertLR() && nChg )
1079 : {
1080 0 : SwRect &rRepaint = *(pPara->GetRepaint());
1081 0 : rRepaint.Left( rRepaint.Left() - nChg );
1082 0 : rRepaint.Width( rRepaint.Width() - nChg );
1083 : }
1084 :
1085 662 : AdjustFrm( nChg, bHasToFit );
1086 :
1087 662 : if( HasFollow() || IsInFtn() )
1088 10 : _AdjustFollow( rLine, nEnd, nStrLen, nNew );
1089 :
1090 662 : pPara->SetPrepMustFit( sal_False );
1091 :
1092 662 : UNDO_SWAP( this )
1093 662 : }
1094 :
1095 : /*************************************************************************
1096 : * SwTxtFrm::FormatLine()
1097 : * bPrev is set whether Reformat.Start() was called because of Prev().
1098 : * Else, wo don't know whether we can limit the repaint or not.
1099 : *************************************************************************/
1100 :
1101 724 : sal_Bool SwTxtFrm::FormatLine( SwTxtFormatter &rLine, const sal_Bool bPrev )
1102 : {
1103 : OSL_ENSURE( ! IsVertical() || IsSwapped(),
1104 : "SwTxtFrm::FormatLine( rLine, bPrev) with unswapped frame" );
1105 724 : SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
1106 724 : const SwLineLayout *pOldCur = rLine.GetCurr();
1107 724 : const xub_StrLen nOldLen = pOldCur->GetLen();
1108 724 : const KSHORT nOldAscent = pOldCur->GetAscent();
1109 724 : const KSHORT nOldHeight = pOldCur->Height();
1110 724 : const SwTwips nOldWidth = pOldCur->Width() + pOldCur->GetHangingMargin();
1111 724 : const sal_Bool bOldHyph = pOldCur->IsEndHyph();
1112 724 : SwTwips nOldTop = 0;
1113 724 : SwTwips nOldBottom = 0;
1114 724 : if( rLine.GetCurr()->IsClipping() )
1115 0 : rLine.CalcUnclipped( nOldTop, nOldBottom );
1116 :
1117 724 : const xub_StrLen nNewStart = rLine.FormatLine( rLine.GetStart() );
1118 :
1119 : OSL_ENSURE( Frm().Pos().Y() + Prt().Pos().Y() == rLine.GetFirstPos(),
1120 : "SwTxtFrm::FormatLine: frame leaves orbit." );
1121 : OSL_ENSURE( rLine.GetCurr()->Height(),
1122 : "SwTxtFrm::FormatLine: line height is zero" );
1123 :
1124 : // The current line break object
1125 724 : const SwLineLayout *pNew = rLine.GetCurr();
1126 :
1127 724 : bool bUnChg = nOldLen == pNew->GetLen() &&
1128 724 : bOldHyph == pNew->IsEndHyph();
1129 724 : if ( bUnChg && !bPrev )
1130 : {
1131 86 : const long nWidthDiff = nOldWidth > pNew->Width()
1132 0 : ? nOldWidth - pNew->Width()
1133 86 : : pNew->Width() - nOldWidth;
1134 :
1135 : // we only declare a line as unchanged, if its main values have not
1136 : // changed and it is not the last line (!paragraph end symbol!)
1137 86 : bUnChg = nOldHeight == pNew->Height() &&
1138 12 : nOldAscent == pNew->GetAscent() &&
1139 : nWidthDiff <= SLOPPY_TWIPS &&
1140 98 : pOldCur->GetNext();
1141 : }
1142 :
1143 : // Calculate rRepaint
1144 724 : const SwTwips nBottom = rLine.Y() + rLine.GetLineHeight();
1145 724 : SwRepaint &rRepaint = *(pPara->GetRepaint());
1146 724 : if( bUnChg && rRepaint.Top() == rLine.Y()
1147 0 : && (bPrev || nNewStart <= pPara->GetReformat()->Start())
1148 0 : && ( nNewStart < GetTxtNode()->GetTxt().Len() ) )
1149 : {
1150 0 : rRepaint.Top( nBottom );
1151 0 : rRepaint.Height( 0 );
1152 : }
1153 : else
1154 : {
1155 724 : if( nOldTop )
1156 : {
1157 0 : if( nOldTop < rRepaint.Top() )
1158 0 : rRepaint.Top( nOldTop );
1159 0 : if( !rLine.IsUnclipped() || nOldBottom > rRepaint.Bottom() )
1160 : {
1161 0 : rRepaint.Bottom( nOldBottom - 1 );
1162 0 : rLine.SetUnclipped( sal_True );
1163 : }
1164 : }
1165 724 : if( rLine.GetCurr()->IsClipping() && rLine.IsFlyInCntBase() )
1166 : {
1167 : SwTwips nTmpTop, nTmpBottom;
1168 3 : rLine.CalcUnclipped( nTmpTop, nTmpBottom );
1169 3 : if( nTmpTop < rRepaint.Top() )
1170 0 : rRepaint.Top( nTmpTop );
1171 3 : if( !rLine.IsUnclipped() || nTmpBottom > rRepaint.Bottom() )
1172 : {
1173 3 : rRepaint.Bottom( nTmpBottom - 1 );
1174 3 : rLine.SetUnclipped( sal_True );
1175 : }
1176 : }
1177 : else
1178 : {
1179 721 : if( !rLine.IsUnclipped() || nBottom > rRepaint.Bottom() )
1180 : {
1181 721 : rRepaint.Bottom( nBottom - 1 );
1182 721 : rLine.SetUnclipped( sal_False );
1183 : }
1184 : }
1185 724 : SwTwips nRght = Max( nOldWidth, pNew->Width() +
1186 724 : pNew->GetHangingMargin() );
1187 724 : ViewShell *pSh = getRootFrm()->GetCurrShell();
1188 724 : const SwViewOption *pOpt = pSh ? pSh->GetViewOptions() : 0;
1189 724 : if( pOpt && (pOpt->IsParagraph() || pOpt->IsLineBreak()) )
1190 0 : nRght += ( Max( nOldAscent, pNew->GetAscent() ) );
1191 : else
1192 724 : nRght += ( Max( nOldAscent, pNew->GetAscent() ) / 4);
1193 724 : nRght += rLine.GetLeftMargin();
1194 724 : if( rRepaint.GetOfst() || rRepaint.GetRightOfst() < nRght )
1195 656 : rRepaint.SetRightOfst( nRght );
1196 :
1197 : // Finally we enlarge the repaint rectangle if we found an underscore
1198 : // within our line. 40 Twips should be enough
1199 : const sal_Bool bHasUnderscore =
1200 724 : ( rLine.GetInfo().GetUnderScorePos() < nNewStart );
1201 724 : if ( bHasUnderscore || rLine.GetCurr()->HasUnderscore() )
1202 6 : rRepaint.Bottom( rRepaint.Bottom() + 40 );
1203 :
1204 724 : ((SwLineLayout*)rLine.GetCurr())->SetUnderscore( bHasUnderscore );
1205 : }
1206 724 : if( !bUnChg )
1207 724 : rLine.SetChanges();
1208 :
1209 : // Calculating the good ol' nDelta
1210 724 : *(pPara->GetDelta()) -= long(pNew->GetLen()) - long(nOldLen);
1211 :
1212 : // Stop!
1213 724 : if( rLine.IsStop() )
1214 0 : return sal_False;
1215 :
1216 : // Absolutely another line
1217 724 : if( rLine.IsNewLine() )
1218 3 : return sal_True;
1219 :
1220 : // Until the String's end?
1221 721 : if( nNewStart >= GetTxtNode()->GetTxt().Len() )
1222 643 : return sal_False;
1223 :
1224 78 : if( rLine.GetInfo().IsShift() )
1225 78 : return sal_True;
1226 :
1227 : // Reached the Reformat's end?
1228 0 : const xub_StrLen nEnd = pPara->GetReformat()->Start() +
1229 0 : pPara->GetReformat()->Len();
1230 :
1231 0 : if( nNewStart <= nEnd )
1232 0 : return sal_True;
1233 :
1234 0 : return 0 != *(pPara->GetDelta());
1235 : }
1236 :
1237 643 : void SwTxtFrm::_Format( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf,
1238 : const sal_Bool bAdjust )
1239 : {
1240 : OSL_ENSURE( ! IsVertical() || IsSwapped(),"SwTxtFrm::_Format with unswapped frame" );
1241 :
1242 643 : SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
1243 643 : rLine.SetUnclipped( sal_False );
1244 :
1245 : // That was too complicated for the C30: aString( GetTxt() );
1246 643 : const XubString &rString = GetTxtNode()->GetTxt();
1247 643 : const xub_StrLen nStrLen = rString.Len();
1248 :
1249 643 : SwCharRange &rReformat = *(pPara->GetReformat());
1250 643 : SwRepaint &rRepaint = *(pPara->GetRepaint());
1251 643 : SwRepaint *pFreeze = NULL;
1252 :
1253 : // Due to performance reasons we set rReformat to STRING_LEN in Init()
1254 : // In this case we adjust rReformat
1255 643 : if( rReformat.Len() > nStrLen )
1256 635 : rReformat.Len() = nStrLen;
1257 :
1258 : // Optimized:
1259 643 : xub_StrLen nEnd = rReformat.Start() + rReformat.Len();
1260 643 : if( nEnd > nStrLen )
1261 : {
1262 0 : rReformat.Len() = nStrLen - rReformat.Start();
1263 0 : nEnd = nStrLen;
1264 : }
1265 :
1266 : SwTwips nOldBottom;
1267 643 : if( GetOfst() && !IsFollow() )
1268 : {
1269 0 : rLine.Bottom();
1270 0 : nOldBottom = rLine.Y();
1271 0 : rLine.Top();
1272 : }
1273 : else
1274 643 : nOldBottom = 0;
1275 643 : rLine.CharToLine( rReformat.Start() );
1276 :
1277 : // Words can be swapped-out when inserting a space into the
1278 : // line that comes before the edited one. That's why we also
1279 : // need to format that.
1280 : // Optimization: If rReformat starts after the first word of the line
1281 : // this line cannot possibly influence the previous one.
1282 : // Unfortunately it can: Text size changes + FlyFrames.
1283 : // The backlash can affect multiple lines (Frame!)!
1284 :
1285 : // #i46560#
1286 : // FME: Yes, consider this case: (word) has to go to the next line
1287 : // because) is a forbidden character at the beginning of a line although
1288 : // (word would still fit on the previous line. Adding text right in front
1289 : // of) would not trigger a reformatting of the previous line. Adding 1
1290 : // to the result of FindBrk() does not solve the problem in all cases,
1291 : // nevertheless it should be sufficient.
1292 643 : bool bPrev = rLine.GetPrev() &&
1293 0 : ( FindBrk( rString, rLine.GetStart(), rReformat.Start() + 1 )
1294 : // #i46560#
1295 : + 1
1296 0 : >= rReformat.Start() ||
1297 643 : rLine.GetCurr()->IsRest() );
1298 643 : if( bPrev )
1299 : {
1300 0 : while( rLine.Prev() )
1301 0 : if( rLine.GetCurr()->GetLen() && !rLine.GetCurr()->IsRest() )
1302 : {
1303 0 : if( !rLine.GetStart() )
1304 0 : rLine.Top(); // So that NumDone doesn't get confused
1305 0 : break;
1306 : }
1307 0 : xub_StrLen nNew = rLine.GetStart() + rLine.GetLength();
1308 0 : if( nNew )
1309 : {
1310 0 : --nNew;
1311 0 : if( CH_BREAK == rString.GetChar( nNew ) )
1312 : {
1313 0 : ++nNew;
1314 0 : rLine.Next();
1315 0 : bPrev = false;
1316 : }
1317 : }
1318 0 : rReformat.Len() += rReformat.Start() - nNew;
1319 0 : rReformat.Start() = nNew;
1320 : }
1321 :
1322 643 : rRepaint.SetOfst( 0 );
1323 643 : rRepaint.SetRightOfst( 0 );
1324 643 : rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() );
1325 643 : if( pPara->IsMargin() )
1326 0 : rRepaint.Width( rRepaint.Width() + pPara->GetHangingMargin() );
1327 643 : rRepaint.Top( rLine.Y() );
1328 643 : if( 0 >= rRepaint.Width() )
1329 0 : rRepaint.Width(1);
1330 643 : WidowsAndOrphans aFrmBreak( this, rInf.IsTest() ? 1 : 0 );
1331 :
1332 : // rLine is now set to the first line which needs formatting.
1333 : // The bFirst flag makes sure that Next() is not called.
1334 : // The whole thing looks weird, but we need to make sure that
1335 : // rLine stops at the last non-fitting line when calling IsBreakNow.
1336 643 : bool bFirst = true;
1337 643 : sal_Bool bFormat = sal_True;
1338 :
1339 : // The CharToLine() can also get us into the danger zone.
1340 : // In that case we need to walk back until rLine is set
1341 : // to the non-fitting line. Or else the mass of text is lost,
1342 : // because the Ofst was set wrongly in the Follow.
1343 :
1344 643 : sal_Bool bBreak = ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 )
1345 643 : && aFrmBreak.IsBreakNowWidAndOrp( rLine );
1346 643 : if( bBreak )
1347 : {
1348 0 : bool bPrevDone = 0 != rLine.Prev();
1349 0 : while( bPrevDone && aFrmBreak.IsBreakNowWidAndOrp(rLine) )
1350 0 : bPrevDone = 0 != rLine.Prev();
1351 0 : if( bPrevDone )
1352 : {
1353 0 : aFrmBreak.SetKeep( sal_False );
1354 0 : rLine.Next();
1355 : }
1356 0 : rLine.TruncLines();
1357 :
1358 : // Play it safe
1359 0 : bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine) &&
1360 0 : ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 );
1361 : }
1362 :
1363 : /* Meaning if the following flags are set:
1364 :
1365 : Watch(End/Mid)Hyph: we need to format if we have a break at
1366 : the line end/Fly, as long as MaxHyph is reached
1367 :
1368 : Jump(End/Mid)Flag: the next line which has no break (line end/Fly),
1369 : needs to be formatted, because we could wrap now. This might have been
1370 : forbidden earlier by MaxHyph
1371 :
1372 : Watch(End/Mid)Hyph: if the last formatted line got a cutoff point, but
1373 : didn't have one before
1374 :
1375 : Jump(End/Mid)Hyph: if a cutoff point disappears
1376 : */
1377 643 : sal_Bool bJumpEndHyph = sal_False,
1378 643 : bWatchEndHyph = sal_False,
1379 643 : bJumpMidHyph = sal_False,
1380 643 : bWatchMidHyph = sal_False;
1381 :
1382 643 : const SwAttrSet& rAttrSet = GetTxtNode()->GetSwAttrSet();
1383 : bool bMaxHyph = ( 0 !=
1384 643 : ( rInf.MaxHyph() = rAttrSet.GetHyphenZone().GetMaxHyphens() ) );
1385 643 : if ( bMaxHyph )
1386 0 : rLine.InitCntHyph();
1387 :
1388 643 : if( IsFollow() && IsFieldFollow() && rLine.GetStart() == GetOfst() )
1389 : {
1390 0 : SwTxtFrm *pMaster = FindMaster();
1391 : OSL_ENSURE( pMaster, "SwTxtFrm::Format: homeless follow" );
1392 0 : const SwLineLayout* pLine=NULL;
1393 0 : if (pMaster)
1394 : {
1395 0 : if( !pMaster->HasPara() )
1396 0 : pMaster->GetFormatted();
1397 0 : SwTxtSizeInfo aInf( pMaster );
1398 0 : SwTxtIter aMasterLine( pMaster, &aInf );
1399 0 : aMasterLine.Bottom();
1400 0 : pLine = aMasterLine.GetCurr();
1401 : }
1402 : SwLinePortion* pRest = pLine ?
1403 0 : rLine.MakeRestPortion(pLine, GetOfst()) : NULL;
1404 0 : if( pRest )
1405 0 : rInf.SetRest( pRest );
1406 : else
1407 0 : SetFieldFollow( sal_False );
1408 : }
1409 :
1410 : /* Ad cancel criterion:
1411 : * In order to recognize, whether a line does not fit onto the page
1412 : * anymore, we need to format it. This overflow is removed again in
1413 : * e.g. AdjustFollow.
1414 : * Another complication: if we are the Master, we need to traverse
1415 : * the lines, because it could happen that one line can overflow
1416 : * from the Follow to the Master.
1417 : */
1418 81 : do
1419 : {
1420 724 : if( bFirst )
1421 643 : bFirst = false;
1422 : else
1423 : {
1424 81 : if ( bMaxHyph )
1425 : {
1426 0 : if ( rLine.GetCurr()->IsEndHyph() )
1427 0 : rLine.CntEndHyph()++;
1428 : else
1429 0 : rLine.CntEndHyph() = 0;
1430 0 : if ( rLine.GetCurr()->IsMidHyph() )
1431 0 : rLine.CntMidHyph()++;
1432 : else
1433 0 : rLine.CntMidHyph() = 0;
1434 : }
1435 81 : if( !rLine.Next() )
1436 : {
1437 81 : if( !bFormat )
1438 : {
1439 : SwLinePortion* pRest =
1440 0 : rLine.MakeRestPortion( rLine.GetCurr(), rLine.GetEnd() );
1441 0 : if( pRest )
1442 0 : rInf.SetRest( pRest );
1443 : }
1444 81 : rLine.Insert( new SwLineLayout() );
1445 81 : rLine.Next();
1446 81 : bFormat = sal_True;
1447 : }
1448 : }
1449 724 : if ( !bFormat && bMaxHyph &&
1450 : (bWatchEndHyph || bJumpEndHyph || bWatchMidHyph || bJumpMidHyph) )
1451 : {
1452 0 : if ( rLine.GetCurr()->IsEndHyph() )
1453 : {
1454 0 : if ( bWatchEndHyph )
1455 0 : bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() );
1456 : }
1457 : else
1458 : {
1459 0 : bFormat = bJumpEndHyph;
1460 0 : bWatchEndHyph = sal_False;
1461 0 : bJumpEndHyph = sal_False;
1462 : }
1463 0 : if ( rLine.GetCurr()->IsMidHyph() )
1464 : {
1465 0 : if ( bWatchMidHyph && !bFormat )
1466 0 : bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() );
1467 : }
1468 : else
1469 : {
1470 0 : bFormat = bFormat || bJumpMidHyph;
1471 0 : bWatchMidHyph = sal_False;
1472 0 : bJumpMidHyph = sal_False;
1473 : }
1474 : }
1475 724 : if( bFormat )
1476 : {
1477 724 : sal_Bool bOldEndHyph = rLine.GetCurr()->IsEndHyph();
1478 724 : sal_Bool bOldMidHyph = rLine.GetCurr()->IsMidHyph();
1479 724 : bFormat = FormatLine( rLine, bPrev );
1480 : // There can only be one bPrev ... (???)
1481 724 : bPrev = sal_False;
1482 724 : if ( bMaxHyph )
1483 : {
1484 0 : if ( rLine.GetCurr()->IsEndHyph() != bOldEndHyph )
1485 : {
1486 0 : bWatchEndHyph = !bOldEndHyph;
1487 0 : bJumpEndHyph = bOldEndHyph;
1488 : }
1489 0 : if ( rLine.GetCurr()->IsMidHyph() != bOldMidHyph )
1490 : {
1491 0 : bWatchMidHyph = !bOldMidHyph;
1492 0 : bJumpMidHyph = bOldMidHyph;
1493 : }
1494 : }
1495 : }
1496 :
1497 724 : if( !rInf.IsNewLine() )
1498 : {
1499 721 : if( !bFormat )
1500 643 : bFormat = 0 != rInf.GetRest();
1501 721 : if( rInf.IsStop() || rInf.GetIdx() >= nStrLen )
1502 643 : break;
1503 78 : if( !bFormat && ( !bMaxHyph || ( !bWatchEndHyph &&
1504 : !bJumpEndHyph && !bWatchMidHyph && !bJumpMidHyph ) ) )
1505 : {
1506 0 : if( GetFollow() )
1507 : {
1508 0 : while( rLine.Next() )
1509 : ; //Nothing
1510 0 : pFreeze = new SwRepaint( rRepaint ); // to minimize painting
1511 : }
1512 : else
1513 0 : break;
1514 : }
1515 : }
1516 81 : bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine);
1517 81 : }while( !bBreak );
1518 :
1519 643 : if( pFreeze )
1520 : {
1521 0 : rRepaint = *pFreeze;
1522 0 : delete pFreeze;
1523 : }
1524 :
1525 643 : if( !rLine.IsStop() )
1526 : {
1527 : // If we're finished formatting the text and we still
1528 : // have other line objects left, these are superfluous
1529 : // now because the text has gotten shorter.
1530 1286 : if( rLine.GetStart() + rLine.GetLength() >= nStrLen &&
1531 643 : rLine.GetCurr()->GetNext() )
1532 : {
1533 0 : rLine.TruncLines();
1534 0 : rLine.SetTruncLines( sal_True );
1535 : }
1536 : }
1537 :
1538 643 : if( !rInf.IsTest() )
1539 : {
1540 : // FormatAdjust does not pay off at OnceMore
1541 643 : if( bAdjust || !rLine.GetDropFmt() || !rLine.CalcOnceMore() )
1542 : {
1543 643 : FormatAdjust( rLine, aFrmBreak, nStrLen, rInf.IsStop() );
1544 : }
1545 643 : if( rRepaint.HasArea() )
1546 643 : SetRepaint();
1547 643 : rLine.SetTruncLines( sal_False );
1548 643 : if( nOldBottom ) // We check whether paragraphs that need scrolling can
1549 : // be shrunk, so that they don't need scrolling anymore
1550 : {
1551 0 : rLine.Bottom();
1552 0 : SwTwips nNewBottom = rLine.Y();
1553 0 : if( nNewBottom < nOldBottom )
1554 0 : _SetOfst( 0 );
1555 : }
1556 : }
1557 643 : }
1558 :
1559 0 : void SwTxtFrm::FormatOnceMore( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf )
1560 : {
1561 : OSL_ENSURE( ! IsVertical() || IsSwapped(),
1562 : "A frame is not swapped in SwTxtFrm::FormatOnceMore" );
1563 :
1564 0 : SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
1565 0 : if( !pPara )
1566 0 : return;
1567 :
1568 : // If necessary the pPara
1569 0 : KSHORT nOld = ((const SwTxtMargin&)rLine).GetDropHeight();
1570 0 : sal_Bool bShrink = sal_False,
1571 0 : bGrow = sal_False,
1572 0 : bGoOn = rLine.IsOnceMore();
1573 0 : sal_uInt8 nGo = 0;
1574 0 : while( bGoOn )
1575 : {
1576 0 : ++nGo;
1577 0 : rInf.Init();
1578 0 : rLine.Top();
1579 0 : if( !rLine.GetDropFmt() )
1580 0 : rLine.SetOnceMore( sal_False );
1581 0 : SwCharRange aRange( 0, rInf.GetTxt().Len() );
1582 0 : *(pPara->GetReformat()) = aRange;
1583 0 : _Format( rLine, rInf );
1584 :
1585 0 : bGoOn = rLine.IsOnceMore();
1586 0 : if( bGoOn )
1587 : {
1588 0 : const KSHORT nNew = ((const SwTxtMargin&)rLine).GetDropHeight();
1589 0 : if( nOld == nNew )
1590 0 : bGoOn = sal_False;
1591 : else
1592 : {
1593 0 : if( nOld > nNew )
1594 0 : bShrink = sal_True;
1595 : else
1596 0 : bGrow = sal_True;
1597 :
1598 0 : if( bShrink == bGrow || 5 < nGo )
1599 0 : bGoOn = sal_False;
1600 :
1601 0 : nOld = nNew;
1602 : }
1603 :
1604 : // If something went wrong, we need to reformat again
1605 0 : if( !bGoOn )
1606 : {
1607 0 : rInf.CtorInitTxtFormatInfo( this );
1608 0 : rLine.CtorInitTxtFormatter( this, &rInf );
1609 0 : rLine.SetDropLines( 1 );
1610 0 : rLine.CalcDropHeight( 1 );
1611 0 : SwCharRange aTmpRange( 0, rInf.GetTxt().Len() );
1612 0 : *(pPara->GetReformat()) = aTmpRange;
1613 0 : _Format( rLine, rInf, sal_True );
1614 : // We paint everything ...
1615 0 : SetCompletePaint();
1616 : }
1617 : }
1618 : }
1619 : }
1620 :
1621 643 : void SwTxtFrm::_Format( SwParaPortion *pPara )
1622 : {
1623 643 : const xub_StrLen nStrLen = GetTxt().Len();
1624 :
1625 643 : if ( !nStrLen )
1626 : {
1627 : // Empty lines do not get tortured for very long:
1628 : // pPara is cleared, which is the same as:
1629 : // *pPara = SwParaPortion;
1630 76 : sal_Bool bMustFit = pPara->IsPrepMustFit();
1631 76 : pPara->Truncate();
1632 76 : pPara->FormatReset();
1633 76 : if( pBlink && pPara->IsBlinking() )
1634 0 : pBlink->Delete( pPara );
1635 :
1636 : // delete pSpaceAdd und pKanaComp
1637 76 : pPara->FinishSpaceAdd();
1638 76 : pPara->FinishKanaComp();
1639 76 : pPara->ResetFlags();
1640 76 : pPara->SetPrepMustFit( bMustFit );
1641 : }
1642 :
1643 : OSL_ENSURE( ! IsSwapped(), "A frame is swapped before _Format" );
1644 :
1645 643 : if ( IsVertical() )
1646 0 : SwapWidthAndHeight();
1647 :
1648 643 : SwTxtFormatInfo aInf( this );
1649 643 : SwTxtFormatter aLine( this, &aInf );
1650 :
1651 643 : HideAndShowObjects();
1652 :
1653 643 : _Format( aLine, aInf );
1654 :
1655 643 : if( aLine.IsOnceMore() )
1656 0 : FormatOnceMore( aLine, aInf );
1657 :
1658 643 : if ( IsVertical() )
1659 0 : SwapWidthAndHeight();
1660 :
1661 : OSL_ENSURE( ! IsSwapped(), "A frame is swapped after _Format" );
1662 :
1663 643 : if( 1 < aLine.GetDropLines() )
1664 : {
1665 0 : if( SVX_ADJUST_LEFT != aLine.GetAdjust() &&
1666 0 : SVX_ADJUST_BLOCK != aLine.GetAdjust() )
1667 : {
1668 0 : aLine.CalcDropAdjust();
1669 0 : aLine.SetPaintDrop( sal_True );
1670 : }
1671 :
1672 0 : if( aLine.IsPaintDrop() )
1673 : {
1674 0 : aLine.CalcDropRepaint();
1675 0 : aLine.SetPaintDrop( sal_False );
1676 : }
1677 643 : }
1678 643 : }
1679 :
1680 : /*************************************************************************
1681 : * SwTxtFrm::Format()
1682 : * We calculate the text frame's size and send a notification.
1683 : * Shrink() or Grow() to adjust the frame's size to the changed required space.
1684 : *************************************************************************/
1685 :
1686 1099 : void SwTxtFrm::Format( const SwBorderAttrs * )
1687 : {
1688 1099 : SWRECTFN( this )
1689 :
1690 1099 : CalcAdditionalFirstLineOffset();
1691 :
1692 : // The range autopilot or the BASIC interface pass us TxtFrms with
1693 : // a width <= 0 from time to time
1694 1099 : if( (Prt().*fnRect->fnGetWidth)() <= 0 )
1695 : {
1696 : // If MustFit is set, we shrink to the Upper's bottom edge if needed.
1697 : // Else we just take a standard size of 12 Pt. (240 twip).
1698 1 : SwTxtLineAccess aAccess( this );
1699 1 : long nFrmHeight = (Frm().*fnRect->fnGetHeight)();
1700 1 : if( aAccess.GetPara()->IsPrepMustFit() )
1701 : {
1702 0 : const SwTwips nLimit = (GetUpper()->*fnRect->fnGetPrtBottom)();
1703 0 : const SwTwips nDiff = - (Frm().*fnRect->fnBottomDist)( nLimit );
1704 0 : if( nDiff > 0 )
1705 0 : Shrink( nDiff );
1706 : }
1707 1 : else if( 240 < nFrmHeight )
1708 0 : Shrink( nFrmHeight - 240 );
1709 1 : else if( 240 > nFrmHeight )
1710 1 : Grow( 240 - nFrmHeight );
1711 1 : nFrmHeight = (Frm().*fnRect->fnGetHeight)();
1712 :
1713 1 : long nTop = (this->*fnRect->fnGetTopMargin)();
1714 1 : if( nTop > nFrmHeight )
1715 0 : (this->*fnRect->fnSetYMargins)( nFrmHeight, 0 );
1716 1 : else if( (Prt().*fnRect->fnGetHeight)() < 0 )
1717 0 : (Prt().*fnRect->fnSetHeight)( 0 );
1718 1 : return;
1719 : }
1720 :
1721 1098 : const xub_StrLen nStrLen = GetTxtNode()->GetTxt().Len();
1722 1098 : if ( nStrLen || !FormatEmpty() )
1723 : {
1724 :
1725 784 : SetEmpty( sal_False );
1726 : // In order to not get confused by nested Formats
1727 784 : FormatLevel aLevel;
1728 784 : if( 12 == aLevel.GetLevel() )
1729 : return;
1730 :
1731 : // We could be possibly not allowed to alter the format information
1732 784 : if( IsLocked() )
1733 : return;
1734 :
1735 : // Attention: Format() could be triggered by GetFormatted()
1736 784 : if( IsHiddenNow() )
1737 : {
1738 0 : long nPrtHeight = (Prt().*fnRect->fnGetHeight)();
1739 0 : if( nPrtHeight )
1740 : {
1741 0 : HideHidden();
1742 0 : Shrink( nPrtHeight );
1743 : }
1744 : else
1745 : {
1746 : // Assure that objects anchored
1747 : // at paragraph resp. at/as character inside paragraph
1748 : // are hidden.
1749 0 : HideAndShowObjects();
1750 : }
1751 0 : ChgThisLines();
1752 : return;
1753 : }
1754 :
1755 : // We do not want to be interrupted during formatting
1756 784 : SwTxtFrmLocker aLock(this);
1757 784 : SwTxtLineAccess aAccess( this );
1758 784 : const bool bNew = !aAccess.SwTxtLineAccess::IsAvailable();
1759 784 : const bool bSetOfst = ( GetOfst() && GetOfst() > GetTxtNode()->GetTxt().Len() );
1760 :
1761 784 : if( CalcPreps() )
1762 : ; // nothing
1763 : // We return if already formatted, but if the TxtFrm was just created
1764 : // and does not have any format information
1765 765 : else if( !bNew && !aAccess.GetPara()->GetReformat()->Len() )
1766 : {
1767 122 : if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() )
1768 : {
1769 0 : aAccess.GetPara()->SetPrepAdjust( sal_True );
1770 0 : aAccess.GetPara()->SetPrep( sal_True );
1771 0 : CalcPreps();
1772 : }
1773 122 : SetWidow( sal_False );
1774 : }
1775 643 : else if( bSetOfst && IsFollow() )
1776 : {
1777 0 : SwTxtFrm *pMaster = FindMaster();
1778 : OSL_ENSURE( pMaster, "SwTxtFrm::Format: homeless follow" );
1779 0 : if( pMaster )
1780 0 : pMaster->Prepare( PREP_FOLLOW_FOLLOWS );
1781 0 : SwTwips nMaxY = (GetUpper()->*fnRect->fnGetPrtBottom)();
1782 0 : if( (Frm().*fnRect->fnOverStep)( nMaxY ) )
1783 0 : (this->*fnRect->fnSetLimit)( nMaxY );
1784 0 : else if( (Frm().*fnRect->fnBottomDist)( nMaxY ) < 0 )
1785 0 : (Frm().*fnRect->fnAddBottom)( -(Frm().*fnRect->fnGetHeight)() );
1786 : }
1787 : else
1788 : {
1789 : // bSetOfst here means that we have the "red arrow situation"
1790 643 : if ( bSetOfst )
1791 0 : _SetOfst( 0 );
1792 :
1793 643 : const sal_Bool bOrphan = IsWidow();
1794 643 : const SwFtnBossFrm* pFtnBoss = HasFtn() ? FindFtnBossFrm() : 0;
1795 643 : SwTwips nFtnHeight = 0;
1796 643 : if( pFtnBoss )
1797 : {
1798 0 : const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont();
1799 0 : nFtnHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0;
1800 : }
1801 0 : do
1802 : {
1803 643 : _Format( aAccess.GetPara() );
1804 643 : if( pFtnBoss && nFtnHeight )
1805 : {
1806 0 : const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont();
1807 0 : SwTwips nNewHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0;
1808 : // If we lost some footnotes, we may have more space
1809 : // for our main text, so we have to format again ...
1810 0 : if( nNewHeight < nFtnHeight )
1811 0 : nFtnHeight = nNewHeight;
1812 : else
1813 0 : break;
1814 : }
1815 : else
1816 643 : break;
1817 : } while ( pFtnBoss );
1818 643 : if( bOrphan )
1819 : {
1820 0 : ValidateFrm();
1821 0 : SetWidow( sal_False );
1822 : }
1823 : }
1824 784 : if( IsEmptyMaster() )
1825 : {
1826 0 : SwFrm* pPre = GetPrev();
1827 0 : if( pPre &&
1828 : // #i10826# It's the first, it cannot keep!
1829 0 : pPre->GetIndPrev() &&
1830 0 : pPre->GetAttrSet()->GetKeep().GetValue() )
1831 : {
1832 0 : pPre->InvalidatePos();
1833 : }
1834 784 : }
1835 : }
1836 :
1837 1098 : ChgThisLines();
1838 :
1839 : // the PrepMustFit should not survive a Format operation
1840 1098 : SwParaPortion *pPara = GetPara();
1841 1098 : if ( pPara )
1842 784 : pPara->SetPrepMustFit( sal_False );
1843 :
1844 1098 : CalcBaseOfstForFly();
1845 1098 : _CalcHeightOfLastLine(); // #i11860#
1846 : }
1847 :
1848 : /*************************************************************************
1849 : * SwTxtFrm::FormatQuick()
1850 : *
1851 : * bForceQuickFormat is set if GetFormatted() has been called during the
1852 : * painting process. Actually I cannot imagine a situation which requires
1853 : * a full formatting of the paragraph during painting, on the other hand
1854 : * a full formatting can cause the invalidation of other layout frames,
1855 : * e.g., if there are footnotes in this paragraph, and invalid layout
1856 : * frames will not calculated during the painting. So I actually want to
1857 : * avoid a formatting during painting, but since I'm a coward, I'll only
1858 : * force the quick formatting in the situation of issue i29062.
1859 : *************************************************************************/
1860 :
1861 0 : sal_Bool SwTxtFrm::FormatQuick( bool bForceQuickFormat )
1862 : {
1863 : OSL_ENSURE( ! IsVertical() || ! IsSwapped(),
1864 : "SwTxtFrm::FormatQuick with swapped frame" );
1865 :
1866 : #if OSL_DEBUG_LEVEL > 1
1867 : const XubString aXXX = GetTxtNode()->GetTxt();
1868 : const SwTwips nDbgY = Frm().Top();
1869 : (void)nDbgY;
1870 : // nStopAt allows CV to alter it
1871 : static MSHORT nStopAt = 0;
1872 : if( nStopAt == GetFrmId() )
1873 : {
1874 : int i = GetFrmId();
1875 : (void)i;
1876 : }
1877 : #endif
1878 :
1879 0 : if( IsEmpty() && FormatEmpty() )
1880 0 : return sal_True;
1881 :
1882 : // We're very picky:
1883 0 : if( HasPara() || IsWidow() || IsLocked()
1884 0 : || !GetValidSizeFlag() ||
1885 0 : ( ( IsVertical() ? Prt().Width() : Prt().Height() ) && IsHiddenNow() ) )
1886 0 : return sal_False;
1887 :
1888 0 : SwTxtLineAccess aAccess( this );
1889 0 : SwParaPortion *pPara = aAccess.GetPara();
1890 0 : if( !pPara )
1891 0 : return sal_False;
1892 :
1893 0 : SwFrmSwapper aSwapper( this, sal_True );
1894 :
1895 0 : SwTxtFrmLocker aLock(this);
1896 0 : SwTxtFormatInfo aInf( this, sal_False, sal_True );
1897 0 : if( 0 != aInf.MaxHyph() ) // Respect MaxHyphen!
1898 0 : return sal_False;
1899 :
1900 0 : SwTxtFormatter aLine( this, &aInf );
1901 :
1902 : // DropCaps are too complicated ...
1903 0 : if( aLine.GetDropFmt() )
1904 0 : return sal_False;
1905 :
1906 0 : xub_StrLen nStart = GetOfst();
1907 0 : const xub_StrLen nEnd = GetFollow()
1908 0 : ? GetFollow()->GetOfst() : aInf.GetTxt().Len();
1909 0 : do
1910 : {
1911 0 : nStart = aLine.FormatLine( nStart );
1912 0 : if( aInf.IsNewLine() || (!aInf.IsStop() && nStart < nEnd) )
1913 0 : aLine.Insert( new SwLineLayout() );
1914 0 : } while( aLine.Next() );
1915 :
1916 : // Last exit: the heights need to match
1917 0 : Point aTopLeft( Frm().Pos() );
1918 0 : aTopLeft += Prt().Pos();
1919 0 : const SwTwips nNewHeight = aLine.Y() + aLine.GetLineHeight();
1920 0 : const SwTwips nOldHeight = aTopLeft.Y() + Prt().Height();
1921 :
1922 0 : if( !bForceQuickFormat && nNewHeight != nOldHeight && !IsUndersized() )
1923 : {
1924 : // Attention: This situation can occur due to FormatLevel==12. Don't panic!
1925 0 : const xub_StrLen nStrt = GetOfst();
1926 0 : _InvalidateRange( SwCharRange( nStrt, nEnd - nStrt) );
1927 0 : return sal_False;
1928 : }
1929 :
1930 0 : if (m_pFollow && nStart != (static_cast<SwTxtFrm*>(m_pFollow))->GetOfst())
1931 0 : return sal_False; // can be caused by e.g. Orphans
1932 :
1933 : // We made it!
1934 :
1935 : // Set repaint
1936 0 : pPara->GetRepaint()->Pos( aTopLeft );
1937 0 : pPara->GetRepaint()->SSize( Prt().SSize() );
1938 :
1939 : // Delete reformat
1940 0 : *(pPara->GetReformat()) = SwCharRange();
1941 0 : *(pPara->GetDelta()) = 0;
1942 :
1943 0 : return sal_True;
1944 : }
1945 :
1946 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|