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