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