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