LCOV - code coverage report
Current view: top level - sw/source/core/text - frmform.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 711 935 76.0 %
Date: 2015-06-13 12:38:46 Functions: 26 27 96.3 %
Legend: Lines: hit not hit

          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: */

Generated by: LCOV version 1.11