/**************************************************************
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"


#include <hintids.hxx>
#include <editeng/keepitem.hxx>
#include <editeng/hyznitem.hxx>
#include <pagefrm.hxx>		// ChangeFtnRef
#include <ndtxt.hxx>		// MakeFrm()
#include <dcontact.hxx>		// SwDrawContact
#include <dflyobj.hxx>		// SwVirtFlyDrawObj
#include <flyfrm.hxx>
#include <ftnfrm.hxx>		// SwFtnFrm
#include <txtftn.hxx>
#include <fmtftn.hxx>
#include <paratr.hxx>
#include <viewopt.hxx>		// SwViewOptions
#include <viewsh.hxx>	  	// ViewShell
#include <frmatr.hxx>
#include <pam.hxx>
#include <flyfrms.hxx>
#include <fmtanchr.hxx>
#include <txtcfg.hxx>
#include <itrform2.hxx> 	// SwTxtFormatter
#include <widorp.hxx>		// Widows and Orphans
#include <txtcache.hxx>
#include <porrst.hxx>		// SwEmptyPortion
#include <blink.hxx>		// pBlink
#include <porfld.hxx>		// SwFldPortion
#include <sectfrm.hxx>		// SwSectionFrm
#include <pormulti.hxx> 	// SwMultiPortion

#include <rootfrm.hxx>
#include <frmfmt.hxx>	  	// SwFrmFmt
// OD 2004-05-24 #i28701#
#include <sortedobjs.hxx>

class FormatLevel
{
	static MSHORT nLevel;
public:
	inline FormatLevel()  { ++nLevel; }
	inline ~FormatLevel() { --nLevel; }
	inline MSHORT GetLevel() const { return nLevel; }
	static sal_Bool LastLevel() { return 10 < nLevel; }
};
MSHORT FormatLevel::nLevel = 0;

/*************************************************************************
 *							ValidateTxt/Frm()
 *************************************************************************/

void ValidateTxt( SwFrm *pFrm )		// Freund vom Frame
{
    if ( ( ! pFrm->IsVertical() &&
             pFrm->Frm().Width() == pFrm->GetUpper()->Prt().Width() ) ||
         (   pFrm->IsVertical() &&
             pFrm->Frm().Height() == pFrm->GetUpper()->Prt().Height() ) )
		pFrm->bValidSize = sal_True;
/*
	pFrm->bValidPrtArea = sal_True;
	//Die Position validieren um nicht unnoetige (Test-)Moves zu provozieren.
	//Dabei darf allerdings nicht eine tatsaechlich falsche Coordinate
	//validiert werden.
	if ( !pFrm->bValidPos )
	{
		//Leider muessen wir dazu die korrekte Position berechnen.
		Point aOld( pFrm->Frm().Pos() );
		pFrm->MakePos();
		if ( aOld != pFrm->Pos() )
		{
			pFrm->Frm().Pos( aOld );
			pFrm->bValidPos = sal_False;
		}
	}
*/
}

void SwTxtFrm::ValidateFrm()
{
	// Umgebung validieren, um Oszillationen zu verhindern.
    SWAP_IF_SWAPPED( this )

    if ( !IsInFly() && !IsInTab() )
	{	//Innerhalb eines Flys nur this validieren, der Rest sollte eigentlich
		//nur fuer Fussnoten notwendig sein und die gibt es innerhalb von
		//Flys nicht. Fix fuer 5544
		SwSectionFrm* pSct = FindSctFrm();
		if( pSct )
		{
			if( !pSct->IsColLocked() )
				pSct->ColLock();
			else
				pSct = NULL;
		}

		SwFrm *pUp = GetUpper();
		pUp->Calc();
		if( pSct )
			pSct->ColUnlock();
	}
	ValidateTxt( this );

	//MA: mindestens das MustFit-Flag muessen wir retten!
	ASSERT( HasPara(), "ResetPreps(), missing ParaPortion." );
	SwParaPortion *pPara = GetPara();
	const sal_Bool bMustFit = pPara->IsPrepMustFit();
	ResetPreps();
	pPara->SetPrepMustFit( bMustFit );

    UNDO_SWAP( this )
}

/*************************************************************************
 *							ValidateBodyFrm()
 *************************************************************************/

// nach einem RemoveFtn muss der BodyFrm und alle innenliegenden kalkuliert
// werden, damit die DeadLine richtig sitzt.
// Erst wird nach aussen hin gesucht, beim Rueckweg werden alle kalkuliert.

void _ValidateBodyFrm( SwFrm *pFrm )
{
    if( pFrm && !pFrm->IsCellFrm() )
	{
        if( !pFrm->IsBodyFrm() && pFrm->GetUpper() )
			_ValidateBodyFrm( pFrm->GetUpper() );
		if( !pFrm->IsSctFrm() )
			pFrm->Calc();
		else
		{
			sal_Bool bOld = ((SwSectionFrm*)pFrm)->IsCntntLocked();
			((SwSectionFrm*)pFrm)->SetCntntLock( sal_True );
			pFrm->Calc();
			if( !bOld )
				((SwSectionFrm*)pFrm)->SetCntntLock( sal_False );
		}
	}
}

void SwTxtFrm::ValidateBodyFrm()
{
    SWAP_IF_SWAPPED( this )

     //siehe Kommtar in ValidateFrm()
    if ( !IsInFly() && !IsInTab() &&
         !( IsInSct() && FindSctFrm()->Lower()->IsColumnFrm() ) )
		_ValidateBodyFrm( GetUpper() );

    UNDO_SWAP( this )
}

/*************************************************************************
 *						SwTxtFrm::FindBodyFrm()
 *************************************************************************/

sal_Bool SwTxtFrm::_GetDropRect( SwRect &rRect ) const
{
    SWAP_IF_NOT_SWAPPED( this )

	ASSERT( HasPara(), "SwTxtFrm::_GetDropRect: try again next year." );
	SwTxtSizeInfo aInf( (SwTxtFrm*)this );
	SwTxtMargin aLine( (SwTxtFrm*)this, &aInf );
	if( aLine.GetDropLines() )
	{
		rRect.Top( aLine.Y() );
		rRect.Left( aLine.GetLineStart() );
		rRect.Height( aLine.GetDropHeight() );
		rRect.Width( aLine.GetDropLeft() );

        if ( IsRightToLeft() )
            SwitchLTRtoRTL( rRect );

        if ( IsVertical() )
            SwitchHorizontalToVertical( rRect );
        UNDO_SWAP( this )
		return sal_True;
	}

    UNDO_SWAP( this )

    return sal_False;
}

/*************************************************************************
 *						SwTxtFrm::FindBodyFrm()
 *************************************************************************/

const SwBodyFrm *SwTxtFrm::FindBodyFrm() const
{
	if ( IsInDocBody() )
	{
		const SwFrm *pFrm = GetUpper();
		while( pFrm && !pFrm->IsBodyFrm() )
			pFrm = pFrm->GetUpper();
		return (const SwBodyFrm*)pFrm;
	}
	return 0;
}

/*************************************************************************
 *						SwTxtFrm::CalcFollow()
 *************************************************************************/

sal_Bool SwTxtFrm::CalcFollow( const xub_StrLen nTxtOfst )
{
    SWAP_IF_SWAPPED( this )

    ASSERT( HasFollow(), "CalcFollow: missing Follow." );

    SwTxtFrm* pMyFollow = GetFollow();

	SwParaPortion *pPara = GetPara();
	sal_Bool bFollowFld = pPara ? pPara->IsFollowField() : sal_False;

    if( !pMyFollow->GetOfst() || pMyFollow->GetOfst() != nTxtOfst ||
        bFollowFld || pMyFollow->IsFieldFollow() ||
        ( pMyFollow->IsVertical() && !pMyFollow->Prt().Width() ) ||
        ( ! pMyFollow->IsVertical() && !pMyFollow->Prt().Height() ) )
	{
#ifdef DBG_UTIL
		const SwFrm *pOldUp = GetUpper();
#endif

        SWRECTFN ( this )
        SwTwips nOldBottom = (GetUpper()->Frm().*fnRect->fnGetBottom)();
        SwTwips nMyPos = (Frm().*fnRect->fnGetTop)();

		const SwPageFrm *pPage = 0;
        sal_Bool  bOldInvaCntnt = sal_True;
        if ( !IsInFly() && GetNext() )
		{
			pPage = FindPageFrm();
			//Minimieren - sprich ggf. zuruecksetzen - der Invalidierungen s.u.
			bOldInvaCntnt  = pPage->IsInvalidCntnt();
        }

        pMyFollow->_SetOfst( nTxtOfst );
        pMyFollow->SetFieldFollow( bFollowFld );
        if( HasFtn() || pMyFollow->HasFtn() )
		{
			ValidateFrm();
			ValidateBodyFrm();
			if( pPara )
			{
				*(pPara->GetReformat()) = SwCharRange();
				*(pPara->GetDelta()) = 0;
			}
		}

		//Der Fussnotenbereich darf sich keinesfalls vergrossern.
		SwSaveFtnHeight aSave( FindFtnBossFrm( sal_True ), LONG_MAX );

        pMyFollow->CalcFtnFlag();
        if ( !pMyFollow->GetNext() && !pMyFollow->HasFtn() )
            nOldBottom = bVert ? 0 : LONG_MAX;

		while( sal_True )
		{
			if( !FormatLevel::LastLevel() )
			{
				// Weenn der Follow in einem spaltigen Bereich oder einem
				// spaltigen Rahmen steckt, muss zunaechst dieser kalkuliert
				// werden, da das FormatWidthCols() nicht funktioniert, wenn
				// es aus dem MakeAll des _gelockten_ Follows heraus gerufen
				// wird.
                SwSectionFrm* pSct = pMyFollow->FindSctFrm();
				if( pSct && !pSct->IsAnLower( this ) )
				{
					if( pSct->GetFollow() )
						pSct->SimpleFormat();
                    else if( ( pSct->IsVertical() && !pSct->Frm().Width() ) ||
                             ( ! pSct->IsVertical() && !pSct->Frm().Height() ) )
						break;
				}
                // OD 14.03.2003 #i11760# - intrinsic format of follow is controlled.
                if ( FollowFormatAllowed() )
                {
                    // OD 14.03.2003 #i11760# - no nested format of follows, if
                    // text frame is contained in a column frame.
                    // Thus, forbid intrinsic format of follow.
                    {
                        bool bIsFollowInColumn = false;
                        SwFrm* pFollowUpper = pMyFollow->GetUpper();
                        while ( pFollowUpper )
                        {
                            if ( pFollowUpper->IsColumnFrm() )
                            {
                                bIsFollowInColumn = true;
                                break;
                            }
                            if ( pFollowUpper->IsPageFrm() ||
                                 pFollowUpper->IsFlyFrm() )
                            {
                                break;
                            }
                            pFollowUpper = pFollowUpper->GetUpper();
                        }
                        if ( bIsFollowInColumn )
                        {
                            pMyFollow->ForbidFollowFormat();
                        }
                    }

                    pMyFollow->Calc();
                    // Der Follow merkt anhand seiner Frm().Height(), dass was schief
                    // gelaufen ist.
                    ASSERT( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: cheesy follow" );
                    if( pMyFollow->GetPrev() )
                    {
                        pMyFollow->Prepare( PREP_CLEAR );
                        pMyFollow->Calc();
                        ASSERT( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: very cheesy follow" );
                    }

                    // OD 14.03.2003 #i11760# - reset control flag for follow format.
                    pMyFollow->AllowFollowFormat();
                }

				//Sicherstellen, dass der Follow gepaintet wird.
                pMyFollow->SetCompletePaint();
			}

			pPara = GetPara();
			//Solange der Follow wg. Orphans Zeilen angefordert, bekommt er
			//diese und wird erneut formatiert, falls moeglich.
			if( pPara && pPara->IsPrepWidows() )
				CalcPreps();
			else
				break;
		}

        if( HasFtn() || pMyFollow->HasFtn() )
		{
			ValidateBodyFrm();
			ValidateFrm();
			if( pPara )
			{
				*(pPara->GetReformat()) = SwCharRange();
				*(pPara->GetDelta()) = 0;
			}
		}

        if ( pPage )
		{
			if ( !bOldInvaCntnt )
				pPage->ValidateCntnt();
        }

#ifdef DBG_UTIL
		ASSERT( pOldUp == GetUpper(), "SwTxtFrm::CalcFollow: heavy follow" );
#endif

        const long nRemaining =
                 - (GetUpper()->Frm().*fnRect->fnBottomDist)( nOldBottom );
        if (  nRemaining > 0 && !GetUpper()->IsSctFrm() &&
              nRemaining != ( bVert ?
                              nMyPos - Frm().Right() :
                              Frm().Top() - nMyPos ) )
        {
            UNDO_SWAP( this )
            return sal_True;
        }
	}

    UNDO_SWAP( this )

    return sal_False;
}

/*************************************************************************
 *						SwTxtFrm::AdjustFrm()
 *************************************************************************/

void SwTxtFrm::AdjustFrm( const SwTwips nChgHght, sal_Bool bHasToFit )
{
    if( IsUndersized() )
	{
		if( GetOfst() && !IsFollow() ) // ein gescrollter Absatz (undersized)
			return;
		SetUndersized( nChgHght == 0 || bHasToFit );
	}

    // AdjustFrm is called with a swapped frame during
    // formatting but the frame is not swapped during FormatEmpty
    SWAP_IF_SWAPPED( this )
    SWRECTFN ( this )

    // Die Size-Variable des Frames wird durch Grow inkrementiert
	// oder durch Shrink dekrementiert. Wenn die Groesse
	// unveraendert ist, soll nichts passieren!
	if( nChgHght >= 0)
	{
        SwTwips nChgHeight = nChgHght;
		if( nChgHght && !bHasToFit )
		{
			if( IsInFtn() && !IsInSct() )
			{
                SwTwips nReal = Grow( nChgHght, sal_True );
				if( nReal < nChgHght )
				{
                    SwTwips nBot = (*fnRect->fnYInc)( (Frm().*fnRect->fnGetBottom)(),
                                                      nChgHght - nReal );
					SwFrm* pCont = FindFtnFrm()->GetUpper();

                    if( (pCont->Frm().*fnRect->fnBottomDist)( nBot ) > 0 )
					{
                        (Frm().*fnRect->fnAddBottom)( nChgHght );
                        if( bVert )
                            Prt().SSize().Width() += nChgHght;
                        else
						Prt().SSize().Height() += nChgHght;
                        UNDO_SWAP( this )
                        return;
					}
				}
			}

            Grow( nChgHght );

			if ( IsInFly() )
			{
				//MA 06. May. 93: Wenn einer der Upper ein Fly ist, so ist es
				//sehr wahrscheinlich, dass dieser Fly durch das Grow seine
				//Position veraendert - also muss auch meine Position korrigiert
				//werden (sonst ist die Pruefung s.u. nicht aussagekraeftig).
				//Die Vorgaenger muessen berechnet werden, damit die Position
				//korrekt berechnet werden kann.
				if ( GetPrev() )
				{
					SwFrm *pPre = GetUpper()->Lower();
					do
					{	pPre->Calc();
						pPre = pPre->GetNext();
					} while ( pPre && pPre != this );
				}
				const Point aOldPos( Frm().Pos() );
				MakePos();
				if ( aOldPos != Frm().Pos() )
                {
                    // OD 2004-07-01 #i28701# - use new method <SwFrm::InvalidateObjs(..)>
                    // No format is performed for the floating screen objects.
                    InvalidateObjs( true );
                }
			}
            nChgHeight = 0;
        }
		// Ein Grow() wird von der Layout-Seite immer akzeptiert,
		// also auch, wenn die FixSize des umgebenden Layoutframes
		// dies nicht zulassen sollte. Wir ueberpruefen diesen
		// Fall und korrigieren die Werte.
		// MA 06. May. 93: Der Frm darf allerdings auch im Notfall nicht
		// weiter geschrumpft werden als es seine Groesse zulaesst.
        SwTwips nRstHeight;
        if ( IsVertical() )
        {
            ASSERT( ! IsSwapped(),"Swapped frame while calculating nRstHeight" );
            
            //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
            if ( IsVertLR() )
            		nRstHeight = GetUpper()->Frm().Left()
                       		+ GetUpper()->Prt().Left()
                       		+ GetUpper()->Prt().Width()
                       		- Frm().Left();
            else
    			nRstHeight = Frm().Left() + Frm().Width() -
                        	( GetUpper()->Frm().Left() + GetUpper()->Prt().Left() );
         }
        else
            nRstHeight = GetUpper()->Frm().Top()
                       + GetUpper()->Prt().Top()
                       + GetUpper()->Prt().Height()
                       - Frm().Top();

		//In Tabellenzellen kann ich mir evtl. noch ein wenig dazuholen, weil
		//durch eine vertikale Ausrichtung auch oben noch Raum sein kann.
        // --> OD 2004-11-25 #115759# - assure, that first lower in upper
        // is the current one or is valid.
        if ( IsInTab() &&
             ( GetUpper()->Lower() == this ||
               GetUpper()->Lower()->IsValid() ) )
        // <--
		{
            long nAdd = (*fnRect->fnYDiff)( (GetUpper()->Lower()->Frm().*fnRect->fnGetTop)(),
                                            (GetUpper()->*fnRect->fnGetPrtTop)() );
            ASSERT( nAdd >= 0, "Ey" );
			nRstHeight += nAdd;
		}

/* ------------------------------------
 * #50964#: nRstHeight < 0 bedeutet, dass der TxtFrm komplett ausserhalb seines
 * Upper liegt. Dies kann passieren, wenn er innerhalb eines FlyAtCntFrm liegt, der
 * durch das Grow() die Seite gewechselt hat. In so einem Fall ist es falsch, der
 * folgenden Grow-Versuch durchzufuehren. Im Bugfall fuehrte dies sogar zur
 * Endlosschleife.
 * -----------------------------------*/
        SwTwips nFrmHeight = (Frm().*fnRect->fnGetHeight)();
        SwTwips nPrtHeight = (Prt().*fnRect->fnGetHeight)();

        if( nRstHeight < nFrmHeight )
		{
			//Kann sein, dass ich die richtige Grosse habe, der Upper aber zu
			//klein ist und der Upper noch Platz schaffen kann.
            if( ( nRstHeight >= 0 || ( IsInFtn() && IsInSct() ) ) && !bHasToFit )
                nRstHeight += GetUpper()->Grow( nFrmHeight - nRstHeight );
            // In spaltigen Bereichen wollen wir moeglichst nicht zu gross werden, damit
			// nicht ueber GetNextSctLeaf weitere Bereiche angelegt werden. Stattdessen
			// schrumpfen wir und notieren bUndersized, damit FormatWidthCols die richtige
			// Spaltengroesse ermitteln kann.
            if ( nRstHeight < nFrmHeight )
			{
				if(	bHasToFit || !IsMoveable() ||
					( IsInSct() && !FindSctFrm()->MoveAllowed(this) ) )
				{
					SetUndersized( sal_True );
                    Shrink( Min( ( nFrmHeight - nRstHeight), nPrtHeight ) );
				}
				else
					SetUndersized( sal_False );
			}
		}
        else if( nChgHeight )
        {
            if( nRstHeight - nFrmHeight < nChgHeight )
                nChgHeight = nRstHeight - nFrmHeight;
            if( nChgHeight )
                Grow( nChgHeight );
        }
    }
    else
        Shrink( -nChgHght );

    UNDO_SWAP( this )
}

/*************************************************************************
 *						SwTxtFrm::AdjustFollow()
 *************************************************************************/

/* AdjustFollow erwartet folgende Situation:
 * Der SwTxtIter steht am unteren Ende des Masters, der Offset wird
 * im Follow eingestellt.
 * nOffset haelt den Offset im Textstring, ab dem der Master abschliesst
 * und der Follow beginnt. Wenn er 0 ist, wird der FolgeFrame geloescht.
 */

void SwTxtFrm::_AdjustFollow( SwTxtFormatter &rLine,
							 const xub_StrLen nOffset, const xub_StrLen nEnd,
							 const sal_uInt8 nMode )
{
    SwFrmSwapper aSwapper( this, sal_False );

    // Wir haben den Rest der Textmasse: alle Follows loeschen
    // Sonderfall sind DummyPortions()
    // - special cases are controlled by parameter <nMode>.
    if( HasFollow() && !(nMode & 1) && nOffset == nEnd )
	{
        while( GetFollow() )
		{
			if( ((SwTxtFrm*)GetFollow())->IsLocked() )
			{
				ASSERT( sal_False, "+SwTxtFrm::JoinFrm: Follow ist locked." );
                return;
			}
			JoinFrm();
		}

        return;
	}

	// Tanz auf dem Vulkan: Wir formatieren eben schnell noch einmal
	// die letzte Zeile fuer das QuoVadis-Geraffel. Selbstverstaendlich
	// kann sich dadurch auch der Offset verschieben:
	const xub_StrLen nNewOfst = ( IsInFtn() && ( !GetIndNext() || HasFollow() ) ) ?
							rLine.FormatQuoVadis(nOffset) : nOffset;

	if( !(nMode & 1) )
	{
		// Wir klauen unseren Follows Textmasse, dabei kann es passieren,
		// dass wir einige Follows Joinen muessen.
		while( GetFollow() && GetFollow()->GetFollow() &&
			   nNewOfst >= GetFollow()->GetFollow()->GetOfst() )
		{
			DBG_LOOP;
			JoinFrm();
		}
	}

	// Der Ofst hat sich verschoben.
	if( GetFollow() )
	{
#if OSL_DEBUG_LEVEL > 1
		static sal_Bool bTest = sal_False;
		if( !bTest || ( nMode & 1 ) )
#endif
		if ( nMode )
			GetFollow()->ManipOfst( 0 );

		if ( CalcFollow( nNewOfst ) )	// CalcFollow erst zum Schluss, dort erfolgt ein SetOfst
			rLine.SetOnceMore( sal_True );
	}
}

/*************************************************************************
 *						SwTxtFrm::JoinFrm()
 *************************************************************************/

SwCntntFrm *SwTxtFrm::JoinFrm()
{
	ASSERT( GetFollow(), "+SwTxtFrm::JoinFrm: no follow" );
	SwTxtFrm  *pFoll = GetFollow();

	SwTxtFrm *pNxt = pFoll->GetFollow();

	// Alle Fussnoten des zu zerstoerenden Follows werden auf uns
	// umgehaengt.
	xub_StrLen nStart = pFoll->GetOfst();
	if ( pFoll->HasFtn() )
	{
		const SwpHints *pHints = pFoll->GetTxtNode()->GetpSwpHints();
		if( pHints )
		{
			SwFtnBossFrm *pFtnBoss = 0;
			SwFtnBossFrm *pEndBoss = 0;
            for ( sal_uInt16 i = 0; i < pHints->Count(); ++i )
            {
				const SwTxtAttr *pHt = (*pHints)[i];
				if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nStart )
				{
					if( pHt->GetFtn().IsEndNote() )
					{
						if( !pEndBoss )
							pEndBoss = pFoll->FindFtnBossFrm();
						pEndBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this );
					}
					else
					{
						if( !pFtnBoss )
							pFtnBoss = pFoll->FindFtnBossFrm( sal_True );
						pFtnBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this );
					}
					SetFtn( sal_True );
				}
			}
		}
	}

#ifdef DBG_UTIL
    else if ( pFoll->GetValidPrtAreaFlag() ||
              pFoll->GetValidSizeFlag() )
    {
		pFoll->CalcFtnFlag();
		ASSERT( !pFoll->HasFtn(), "Missing FtnFlag." );
	}
#endif

	pFoll->MoveFlyInCnt( this, nStart, STRING_LEN );
    pFoll->SetFtn( sal_False );
    // --> OD 2005-12-01 #i27138#
    // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation.
    // Relation CONTENT_FLOWS_FROM for current next paragraph will change
    // and relation CONTENT_FLOWS_TO for current previous paragraph, which
    // is <this>, will change.
    {
        ViewShell* pViewShell( pFoll->getRootFrm()->GetCurrShell() );
        if ( pViewShell && pViewShell->GetLayout() &&
             pViewShell->GetLayout()->IsAnyShellAccessible() )
        {
            pViewShell->InvalidateAccessibleParaFlowRelation(
                            dynamic_cast<SwTxtFrm*>(pFoll->FindNextCnt( true )),
                            this );
        }
    }
    // <--
    pFoll->Cut();
	delete pFoll;
	pFollow = pNxt;
	return pNxt;
}

/*************************************************************************
 *						SwTxtFrm::SplitFrm()
 *************************************************************************/

SwCntntFrm *SwTxtFrm::SplitFrm( const xub_StrLen nTxtPos )
{
    SWAP_IF_SWAPPED( this )

	// Durch das Paste wird ein Modify() an mich verschickt.
	// Damit meine Daten nicht verschwinden, locke ich mich.
	SwTxtFrmLocker aLock( this );
	SwTxtFrm *pNew = (SwTxtFrm *)(GetTxtNode()->MakeFrm( this ));
	pNew->bIsFollow = sal_True;

	pNew->SetFollow( GetFollow() );
	SetFollow( pNew );

	pNew->Paste( GetUpper(), GetNext() );
    // --> OD 2005-12-01 #i27138#
    // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation.
    // Relation CONTENT_FLOWS_FROM for current next paragraph will change
    // and relation CONTENT_FLOWS_TO for current previous paragraph, which
    // is <this>, will change.
    {
        ViewShell* pViewShell( pNew->getRootFrm()->GetCurrShell() );
        if ( pViewShell && pViewShell->GetLayout() &&
             pViewShell->GetLayout()->IsAnyShellAccessible() )
        {
            pViewShell->InvalidateAccessibleParaFlowRelation(
                            dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )),
                            this );
        }
    }
    // <--

	// Wenn durch unsere Aktionen Fussnoten in pNew landen,
	// so muessen sie umgemeldet werden.
	if ( HasFtn() )
	{
		const SwpHints *pHints = GetTxtNode()->GetpSwpHints();
		if( pHints )
		{
			SwFtnBossFrm *pFtnBoss = 0;
			SwFtnBossFrm *pEndBoss = 0;
            for ( sal_uInt16 i = 0; i < pHints->Count(); ++i )
            {
				const SwTxtAttr *pHt = (*pHints)[i];
				if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nTxtPos )
				{
					if( pHt->GetFtn().IsEndNote() )
					{
						if( !pEndBoss )
							pEndBoss = FindFtnBossFrm();
						pEndBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew );
					}
					else
					{
						if( !pFtnBoss )
							pFtnBoss = FindFtnBossFrm( sal_True );
						pFtnBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew );
					}
					pNew->SetFtn( sal_True );
				}
			}
		}
	}

#ifdef DBG_UTIL
	else
	{
		CalcFtnFlag( nTxtPos-1 );
		ASSERT( !HasFtn(), "Missing FtnFlag." );
	}
#endif

	MoveFlyInCnt( pNew, nTxtPos, STRING_LEN );

	// Kein SetOfst oder CalcFollow, weil gleich ohnehin ein AdjustFollow folgt.

	pNew->ManipOfst( nTxtPos );

    UNDO_SWAP( this )
	return pNew;
}


/*************************************************************************
 *						virtual SwTxtFrm::SetOfst()
 *************************************************************************/

void SwTxtFrm::_SetOfst( const xub_StrLen nNewOfst )
{
#ifdef DBGTXT
	// Es gibt tatsaechlich einen Sonderfall, in dem ein SetOfst(0)
	// zulaessig ist: bug 3496
	ASSERT( nNewOfst, "!SwTxtFrm::SetOfst: missing JoinFrm()." );
#endif

	// Die Invalidierung unseres Follows ist nicht noetig.
	// Wir sind ein Follow, werden gleich formatiert und
	// rufen von dort aus das SetOfst() !
	nOfst = nNewOfst;
	SwParaPortion *pPara = GetPara();
	if( pPara )
	{
		SwCharRange &rReformat = *(pPara->GetReformat());
		rReformat.Start() = 0;
		rReformat.Len() = GetTxt().Len();
		*(pPara->GetDelta()) = rReformat.Len();
	}
	InvalidateSize();
}

/*************************************************************************
 *						SwTxtFrm::CalcPreps
 *************************************************************************/

sal_Bool SwTxtFrm::CalcPreps()
{
    ASSERT( ! IsVertical() || ! IsSwapped(), "SwTxtFrm::CalcPreps with swapped frame" );
    SWRECTFN( this );

    SwParaPortion *pPara = GetPara();
	if ( !pPara )
		return sal_False;
	sal_Bool bPrep = pPara->IsPrep();
	sal_Bool bPrepWidows = pPara->IsPrepWidows();
	sal_Bool bPrepAdjust = pPara->IsPrepAdjust();
	sal_Bool bPrepMustFit = pPara->IsPrepMustFit();
	ResetPreps();

	sal_Bool bRet = sal_False;
	if( bPrep && !pPara->GetReformat()->Len() )
	{
		// PREP_WIDOWS bedeutet, dass im Follow die Orphans-Regel
		// zuschlug.
		// Es kann in unguenstigen Faellen vorkommen, dass auch ein
		// PrepAdjust vorliegt (3680)!
		if( bPrepWidows )
		{
			if( !GetFollow() )
			{
				ASSERT( GetFollow(), "+SwTxtFrm::CalcPreps: no credits" );
				return sal_False;
			}

			// Wir muessen uns auf zwei Faelle einstellen:
			// Wir konnten dem Follow noch ein paar Zeilen abgeben,
			// -> dann muessen wir schrumpfen
			// oder wir muessen auf die naechste Seite
			// -> dann lassen wir unseren Frame zu gross werden.

			SwTwips nChgHeight = GetParHeight();
            if( nChgHeight >= (Prt().*fnRect->fnGetHeight)() )
			{
				if( bPrepMustFit )
				{
					GetFollow()->SetJustWidow( sal_True );
					GetFollow()->Prepare( PREP_CLEAR );
				}
                else if ( bVert )
				{
                    Frm().Width( Frm().Width() + Frm().Left() );
                    Prt().Width( Prt().Width() + Frm().Left() );
                    Frm().Left( 0 );
					SetWidow( sal_True );
				}
                else
				{
					SwTwips nTmp  = LONG_MAX - (Frm().Top()+10000);
					SwTwips nDiff = nTmp - Frm().Height();
					Frm().Height( nTmp );
					Prt().Height( Prt().Height() + nDiff );
					SetWidow( sal_True );
				}
			}
			else
			{
                ASSERT( nChgHeight < (Prt().*fnRect->fnGetHeight)(),
						"+SwTxtFrm::CalcPrep: wanna shrink" );

                nChgHeight = (Prt().*fnRect->fnGetHeight)() - nChgHeight;

				GetFollow()->SetJustWidow( sal_True );
				GetFollow()->Prepare( PREP_CLEAR );
                Shrink( nChgHeight );
				SwRect &rRepaint = *(pPara->GetRepaint());

                if ( bVert )
                {
                    SwRect aRepaint( Frm().Pos() + Prt().Pos(), Prt().SSize() );
                    SwitchVerticalToHorizontal( aRepaint );
                    rRepaint.Chg( aRepaint.Pos(), aRepaint.SSize() );
                }
                else
                    rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() );

				// 6792: Rrand < LRand und Repaint
                if( 0 >= rRepaint.Width() )
					rRepaint.Width(1);
			}
			bRet = sal_True;
		}

		else if ( bPrepAdjust )
		{
			if ( HasFtn() )
			{
				if( !CalcPrepFtnAdjust() )
				{
					if( bPrepMustFit )
					{
						SwTxtLineAccess aAccess( this );
						aAccess.GetPara()->SetPrepMustFit( sal_True );
					}
					return sal_False;
				}
			}

            SWAP_IF_NOT_SWAPPED( this )

			SwTxtFormatInfo aInf( this );
			SwTxtFormatter aLine( this, &aInf );

			WidowsAndOrphans aFrmBreak( this );
			// Egal was die Attribute meinen, bei MustFit wird
			// der Absatz im Notfall trotzdem gesplittet...
			if( bPrepMustFit )
			{
				aFrmBreak.SetKeep( sal_False );
				aFrmBreak.ClrOrphLines();
			}
			// Bevor wir FormatAdjust aufrufen muessen wir dafuer
			// sorgen, dass die Zeilen, die unten raushaengen
			// auch tatsaechlich abgeschnitten werden.
            // OD 2004-02-25 #i16128# - method renamed
            sal_Bool bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine );
			bRet = sal_True;
			while( !bBreak && aLine.Next() )
            {
                // OD 2004-02-25 #i16128# - method renamed
                bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine );
            }
			if( bBreak )
			{
				// Es gibt Komplikationen: wenn TruncLines gerufen wird,
				// veraendern sich ploetzlich die Bedingungen in
				// IsInside, so dass IsBreakNow andere Ergebnisse
				// liefern kann. Aus diesem Grund wird rFrmBreak bekannt
				// gegeben, dass da wo rLine steht, das Ende erreicht
				// ist. Mal sehen, ob's klappt ...
				aLine.TruncLines();
				aFrmBreak.SetRstHeight( aLine );
                FormatAdjust( aLine, aFrmBreak, aInf.GetTxt().Len(), aInf.IsStop() );
			}
			else
			{
				if( !GetFollow() )
                {
					FormatAdjust( aLine, aFrmBreak,
                                  aInf.GetTxt().Len(), aInf.IsStop() );
                }
				else if ( !aFrmBreak.IsKeepAlways() )
				{
					// Siehe Bug: 2320
					// Vor dem Master wird eine Zeile geloescht, der Follow
					// koennte eine Zeile abgeben.
					const SwCharRange aFollowRg( GetFollow()->GetOfst(), 1 );
					*(pPara->GetReformat()) += aFollowRg;
					// Es soll weitergehen!
					bRet = sal_False;
				}
			}

            UNDO_SWAP( this )
            // Eine letzte Ueberpruefung, falls das FormatAdjust() nichts
			// brachte, muessen wir amputieren.
			if( bPrepMustFit )
			{
                const SwTwips nMust = (GetUpper()->*fnRect->fnGetPrtBottom)();
                const SwTwips nIs   = (Frm().*fnRect->fnGetBottom)();

                if( bVert && nIs < nMust )
                {
                    Shrink( nMust - nIs );
                    if( Prt().Width() < 0 )
                        Prt().Width( 0 );
					SetUndersized( sal_True );
                }
                else if ( ! bVert && nIs > nMust )
                {
                    Shrink( nIs - nMust );
					if( Prt().Height() < 0 )
						Prt().Height( 0 );
					SetUndersized( sal_True );
				}
			}
		}
	}
	pPara->SetPrepMustFit( bPrepMustFit );
	return bRet;
}


/*************************************************************************
 *						SwTxtFrm::FormatAdjust()
 *************************************************************************/

// Hier werden die Fussnoten und "als Zeichen"-gebundenen Objekte umgehaengt
#define CHG_OFFSET( pFrm, nNew )\
	{\
		if( pFrm->GetOfst() < nNew )\
			pFrm->MoveFlyInCnt( this, 0, nNew );\
		else if( pFrm->GetOfst() > nNew )\
			MoveFlyInCnt( pFrm, nNew, STRING_LEN );\
	}

void SwTxtFrm::FormatAdjust( SwTxtFormatter &rLine,
							 WidowsAndOrphans &rFrmBreak,
                             const xub_StrLen nStrLen,
                             const sal_Bool bDummy )
{
    SWAP_IF_NOT_SWAPPED( this )

    SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();

	xub_StrLen nEnd = rLine.GetStart();

	sal_Bool bHasToFit = pPara->IsPrepMustFit();

	// Das StopFlag wird durch Fussnoten gesetzt,
	// die auf die naechste Seite wollen.
    // OD, FME 2004-03-03 - call base class method <SwTxtFrmBreak::IsBreakNow(..)>
    // instead of method <WidowsAndOrphans::IsBreakNow(..)> to get a break,
    // even if due to widow rule no enough lines exists.
    sal_uInt8 nNew = ( !GetFollow() &&
                       nEnd < nStrLen &&
                       ( rLine.IsStop() ||
                         ( bHasToFit
                           ? ( rLine.GetLineNr() > 1 &&
                               !rFrmBreak.IsInside( rLine ) )
                           : rFrmBreak.IsBreakNow( rLine ) ) ) )
                     ? 1 : 0;
    // --> OD #i84870#
    // no split of text frame, which only contains a as-character anchored object
    const bool bOnlyContainsAsCharAnchoredObj =
            !IsFollow() && nStrLen == 1 &&
            GetDrawObjs() && GetDrawObjs()->Count() == 1 &&
            (*GetDrawObjs())[0]->GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AS_CHAR;
    if ( nNew && bOnlyContainsAsCharAnchoredObj )
    {
        nNew = 0;
    }
    // <--
    if ( nNew )
	{
		SplitFrm( nEnd );
	}

	const SwFrm *pBodyFrm = (const SwFrm*)(FindBodyFrm());

    const long nBodyHeight = pBodyFrm ? ( IsVertical() ?
                                          pBodyFrm->Frm().Width() :
                                          pBodyFrm->Frm().Height() ) : 0;

	// Wenn die aktuellen Werte berechnet wurden, anzeigen, dass
	// sie jetzt gueltig sind.
	*(pPara->GetReformat()) = SwCharRange();
	sal_Bool bDelta = *pPara->GetDelta() != 0;
	*(pPara->GetDelta()) = 0;

	if( rLine.IsStop() )
	{
		rLine.TruncLines( sal_True );
		nNew = 1;
	}

	// FindBreak schneidet die letzte Zeile ab.
	if( !rFrmBreak.FindBreak( this, rLine, bHasToFit ) )
	{
		// Wenn wir bis zum Ende durchformatiert haben, wird nEnd auf das Ende
		// gesetzt. In AdjustFollow wird dadurch ggf. JoinFrm() ausgefuehrt.
		// Ansonsten ist nEnd das Ende der letzten Zeile im Master.
		xub_StrLen nOld = nEnd;
		nEnd = rLine.GetEnd();
		if( GetFollow() )
		{
			if( nNew && nOld < nEnd )
				RemoveFtn( nOld, nEnd - nOld );
			CHG_OFFSET( GetFollow(), nEnd )
			if( !bDelta )
				GetFollow()->ManipOfst( nEnd );
		}
	}
	else
	{   // Wenn wir Zeilen abgeben, darf kein Join auf den Folows gerufen werden,
		// im Gegenteil, es muss ggf. sogar ein Follow erzeugt werden.
		// Dies muss auch geschehen, wenn die Textmasse komplett im Master
		// bleibt, denn es k???nnte ja ein harter Zeilenumbruch noch eine weitere
		// Zeile (ohne Textmassse) notwendig machen!
		nEnd = rLine.GetEnd();
		if( GetFollow() )
		{
            // OD 21.03.2003 #108121# - Another case for not joining the follow:
            // Text frame has no content, but a numbering. Then, do *not* join.
            // Example of this case: When an empty, but numbered paragraph
            // at the end of page is completely displaced by a fly frame.
            // Thus, the text frame introduced a follow by a
            // <SwTxtFrm::SplitFrm(..)> - see below. The follow then shows
            // the numbering and must stay.
            if ( GetFollow()->GetOfst() != nEnd ||
                 GetFollow()->IsFieldFollow() ||
                 ( nStrLen == 0 && GetTxtNode()->GetNumRule() ) )
            {
				nNew |= 3;
            }
			CHG_OFFSET( GetFollow(), nEnd )
			GetFollow()->ManipOfst( nEnd );
		}
		else
		{
            // OD 21.03.2003 #108121# - Only split frame, if the frame contains
            // content or contains no content, but has a numbering.
            // OD #i84870# - no split, if text frame only contains one
            // as-character anchored object.
            if ( !bOnlyContainsAsCharAnchoredObj &&
                 ( nStrLen > 0 ||
                   ( nStrLen == 0 && GetTxtNode()->GetNumRule() ) )
               )
            {
                SplitFrm( nEnd );
                nNew |= 3;
            }
		}
		// Wenn sich die Resthoehe geaendert hat, z.B. durch RemoveFtn()
		// dann muessen wir auffuellen, um Oszillationen zu vermeiden!
        if( bDummy && pBodyFrm &&
           nBodyHeight < ( IsVertical() ?
                           pBodyFrm->Frm().Width() :
                           pBodyFrm->Frm().Height() ) )
			rLine.MakeDummyLine();
	}

	// In AdjustFrm() stellen wir uns selbst per Grow/Shrink ein,
	// in AdjustFollow() stellen wir unseren FolgeFrame ein.

	const SwTwips nDocPrtTop = Frm().Top() + Prt().Top();
	const SwTwips nOldHeight = Prt().SSize().Height();
    SwTwips nChg = rLine.CalcBottomLine() - nDocPrtTop - nOldHeight;
    // --> OD #i84870# - no shrink of text frame, if it only contains one 
    // as-character anchored object.
    if ( nChg < 0 &&
         bOnlyContainsAsCharAnchoredObj )
    {
        nChg = 0;
    }
    // <--

    // Vertical Formatting:
    // The (rotated) repaint rectangle's x coordinate referes to the frame.
    // If the frame grows (or shirks) the repaint rectangle cannot simply
    // be rotated back after formatting, because we use the upper left point
    // of the frame for rotation. This point changes when growing/shrinking.
    
    //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
    if ( IsVertical() && !IsVertLR() && nChg )
    {
        SwRect &rRepaint = *(pPara->GetRepaint());
        rRepaint.Left( rRepaint.Left() - nChg );
        rRepaint.Width( rRepaint.Width() - nChg );
    }

    AdjustFrm( nChg, bHasToFit );

/*
    // FME 16.07.2003 #i16930# - removed this code because it did not
    // work correctly. In SwCntntFrm::MakeAll, the frame did not move to the
    // next page, instead the print area was recalculated and
    // Prepare( PREP_POS_CHGD, (const void*)&bFormatted, sal_False ) invalidated
    // the other flags => loop

    // OD 04.04.2003 #108446# - handle special case:
    // If text frame contains no content and just has split, because of a
    // line stop, it has to move forward. To force this forward move without
    // unnecessary formatting of its footnotes and its follow, especially in
    // columned sections, adjust frame height to zero (0) and do not perform
    // the intrinsic format of the follow.
    // The formating method <SwCntntFrm::MakeAll()> will initiate the move forward.
    sal_Bool bForcedNoIntrinsicFollowCalc = sal_False;
    if ( nEnd == 0 &&
         rLine.IsStop() && HasFollow() && nNew == 1
       )
    {
        AdjustFrm( -Frm().SSize().Height(), bHasToFit );
        Prt().Pos().Y() = 0;
        Prt().Height( Frm().Height() );
        if ( FollowFormatAllowed() )
        {
            bForcedNoIntrinsicFollowCalc = sal_True;
            ForbidFollowFormat();
        }
    }
    else
    {
        AdjustFrm( nChg, bHasToFit );
    }
 */

    if( HasFollow() || IsInFtn() )
		_AdjustFollow( rLine, nEnd, nStrLen, nNew );

    // FME 16.07.2003 #i16930# - removed this code because it did not work
    // correctly
    // OD 04.04.2003 #108446# - allow intrinsic format of follow, if above
    // special case has forbit it.
/*    if ( bForcedNoIntrinsicFollowCalc )
    {
        AllowFollowFormat();
    }
 */

    pPara->SetPrepMustFit( sal_False );

    UNDO_SWAP( this )
}

/*************************************************************************
 *						SwTxtFrm::FormatLine()
 *************************************************************************/

// bPrev zeigt an, ob Reformat.Start() wegen Prev() vorgezogen wurde.
// Man weiss sonst nicht, ob man Repaint weiter einschraenken kann oder nicht.


sal_Bool SwTxtFrm::FormatLine( SwTxtFormatter &rLine, const sal_Bool bPrev )
{
    ASSERT( ! IsVertical() || IsSwapped(),
            "SwTxtFrm::FormatLine( rLine, bPrev) with unswapped frame" );
	SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
	// Nach rLine.FormatLine() haelt nStart den neuen Wert,
	// waehrend in pOldStart der alte Offset gepflegt wird.
	// Ueber diesen Weg soll das nDelta ersetzt werden.
	// *pOldStart += rLine.GetCurr()->GetLen();
	const SwLineLayout *pOldCur = rLine.GetCurr();
	const xub_StrLen nOldLen    = pOldCur->GetLen();
	const KSHORT nOldAscent = pOldCur->GetAscent();
	const KSHORT nOldHeight = pOldCur->Height();
	const SwTwips nOldWidth	= pOldCur->Width() + pOldCur->GetHangingMargin();
	const sal_Bool bOldHyph = pOldCur->IsEndHyph();
	SwTwips nOldTop = 0;
	SwTwips nOldBottom = 0;
	if( rLine.GetCurr()->IsClipping() )
		rLine.CalcUnclipped( nOldTop, nOldBottom );

	const xub_StrLen nNewStart = rLine.FormatLine( rLine.GetStart() );

    ASSERT( Frm().Pos().Y() + Prt().Pos().Y() == rLine.GetFirstPos(),
			"SwTxtFrm::FormatLine: frame leaves orbit." );
	ASSERT( rLine.GetCurr()->Height(),
			"SwTxtFrm::FormatLine: line height is zero" );

	// Das aktuelle Zeilenumbruchobjekt.
	const SwLineLayout *pNew = rLine.GetCurr();

	sal_Bool bUnChg = nOldLen == pNew->GetLen() &&
				  bOldHyph == pNew->IsEndHyph();
	if ( bUnChg && !bPrev )
	{
		// 6672: Toleranz von SLOPPY_TWIPS (5 Twips); vgl. 6922
		const long nWidthDiff = nOldWidth > pNew->Width()
								? nOldWidth - pNew->Width()
								: pNew->Width() - nOldWidth;

        // we only declare a line as unchanged, if its main values have not
        // changed and it is not the last line (!paragraph end symbol!)
		bUnChg = nOldHeight == pNew->Height() &&
				 nOldAscent == pNew->GetAscent() &&
                 nWidthDiff <= SLOPPY_TWIPS &&
                 pOldCur->GetNext();
	}

	// rRepaint wird berechnet:
	const SwTwips nBottom = rLine.Y() + rLine.GetLineHeight();
	SwRepaint &rRepaint = *(pPara->GetRepaint());
	if( bUnChg && rRepaint.Top() == rLine.Y()
			   && (bPrev || nNewStart <= pPara->GetReformat()->Start())
			   && ( nNewStart < GetTxtNode()->GetTxt().Len() ) )
	{
		rRepaint.Top( nBottom );
		rRepaint.Height( 0 );
	}
	else
	{
		if( nOldTop )
		{
			if( nOldTop < rRepaint.Top() )
				rRepaint.Top( nOldTop );
			if( !rLine.IsUnclipped() || nOldBottom > rRepaint.Bottom() )
			{
				rRepaint.Bottom( nOldBottom - 1 );
				rLine.SetUnclipped( sal_True );
			}
		}
		if( rLine.GetCurr()->IsClipping() && rLine.IsFlyInCntBase() )
		{
			SwTwips nTmpTop, nTmpBottom;
			rLine.CalcUnclipped( nTmpTop, nTmpBottom );
			if( nTmpTop < rRepaint.Top() )
				rRepaint.Top( nTmpTop );
			if( !rLine.IsUnclipped() || nTmpBottom > rRepaint.Bottom() )
			{
				rRepaint.Bottom( nTmpBottom - 1 );
				rLine.SetUnclipped( sal_True );
			}
		}
		else
		{
			if( !rLine.IsUnclipped() || nBottom > rRepaint.Bottom() )
			{
				rRepaint.Bottom( nBottom - 1 );
				rLine.SetUnclipped( sal_False );
			}
		}
		SwTwips nRght = Max( nOldWidth, pNew->Width() +
							 pNew->GetHangingMargin() );
		ViewShell *pSh = getRootFrm()->GetCurrShell();
		const SwViewOption *pOpt = pSh ? pSh->GetViewOptions() : 0;
		if( pOpt && (pOpt->IsParagraph() || pOpt->IsLineBreak()) )
			nRght += ( Max( nOldAscent, pNew->GetAscent() ) );
		else
			nRght += ( Max( nOldAscent, pNew->GetAscent() ) / 4);
		nRght += rLine.GetLeftMargin();
		if( rRepaint.GetOfst() || rRepaint.GetRightOfst() < nRght )
			rRepaint.SetRightOfst( nRght );

        // Finally we enlarge the repaint rectangle if we found an underscore
        // within our line. 40 Twips should be enough
        const sal_Bool bHasUnderscore =
                ( rLine.GetInfo().GetUnderScorePos() < nNewStart );
        if ( bHasUnderscore || rLine.GetCurr()->HasUnderscore() )
            rRepaint.Bottom( rRepaint.Bottom() + 40 );

        ((SwLineLayout*)rLine.GetCurr())->SetUnderscore( bHasUnderscore );
	}
	if( !bUnChg )
		rLine.SetChanges();

	// Die gute, alte nDelta-Berechnung:
	*(pPara->GetDelta()) -= long(pNew->GetLen()) - long(nOldLen);

	// Stop!
	if( rLine.IsStop() )
		return sal_False;

	// Unbedingt noch eine Zeile
	if( rLine.IsNewLine() )
		return sal_True;

	// bis zum Ende des Strings ?
	if( nNewStart >= GetTxtNode()->GetTxt().Len() )
		return sal_False;

	if( rLine.GetInfo().IsShift() )
		return sal_True;

	// Ende des Reformats erreicht ?
	const xub_StrLen nEnd = pPara->GetReformat()->Start() +
						pPara->GetReformat()->Len();

	if( nNewStart <= nEnd )
		return sal_True;

	return 0 != *(pPara->GetDelta());
}

/*************************************************************************
 *						SwTxtFrm::_Format()
 *************************************************************************/

void SwTxtFrm::_Format( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf,
						const sal_Bool bAdjust )
{
    ASSERT( ! IsVertical() || IsSwapped(),"SwTxtFrm::_Format with unswapped frame" );

    SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
	rLine.SetUnclipped( sal_False );

	// Das war dem C30 zu kompliziert: aString( GetTxt() );
	const XubString &rString = GetTxtNode()->GetTxt();
	const xub_StrLen nStrLen = rString.Len();

	SwCharRange &rReformat = *(pPara->GetReformat());
	SwRepaint	&rRepaint = *(pPara->GetRepaint());
	SwRepaint *pFreeze = NULL;

	// Aus Performancegruenden wird in Init() rReformat auf STRING_LEN gesetzt.
	// Fuer diesen Fall wird rReformat angepasst.
	if( rReformat.Len() > nStrLen )
		rReformat.Len() = nStrLen;

	// Optimiert:
	xub_StrLen nEnd = rReformat.Start() + rReformat.Len();
	if( nEnd > nStrLen )
	{
		rReformat.Len() = nStrLen - rReformat.Start();
		nEnd = nStrLen;
	}

	SwTwips nOldBottom;
	if( GetOfst() && !IsFollow() )
	{
		rLine.Bottom();
		nOldBottom = rLine.Y();
		rLine.Top();
	}
	else
		nOldBottom = 0;
	rLine.CharToLine( rReformat.Start() );

	// Worte koennen durch Fortfall oder Einfuegen eines Space
	// auf die Zeile vor der editierten hinausgezogen werden,
	// deshalb muss diese ebenfalls formatiert werden.
	// Optimierung: Wenn rReformat erst hinter dem ersten Wort der
	// Zeile beginnt, so kann diese Zeile die vorige nicht mehr beeinflussen.
	// AMA: Leider doch, Textgroessenaenderungen + FlyFrames, die Rueckwirkung
	// kann im Extremfall mehrere Zeilen (Frames!!!) betreffen!

    // --> FME 2005-04-18 #i46560#
    // FME: Yes, consider this case: (word ) has to go to the next line
    // because ) is a forbidden character at the beginning of a line although
    // (word would still fit on the previous line. Adding text right in front
    // of ) would not trigger a reformatting of the previous line. Adding 1
    // to the result of FindBrk() does not solve the problem in all cases,
    // nevertheless it should be sufficient.
    // <--
    sal_Bool bPrev = rLine.GetPrev() &&
                     ( FindBrk( rString, rLine.GetStart(), rReformat.Start() + 1 )
                       // --> FME 2005-04-18 #i46560#
                       + 1
                       // <--
                       >= rReformat.Start() ||
                       rLine.GetCurr()->IsRest() );
    if( bPrev )
	{
		while( rLine.Prev() )
			if( rLine.GetCurr()->GetLen() && !rLine.GetCurr()->IsRest() )
			{
				if( !rLine.GetStart() )
					rLine.Top(); // damit NumDone nicht durcheinander kommt
				break;
			}
		xub_StrLen nNew = rLine.GetStart() + rLine.GetLength();
		if( nNew )
		{
			--nNew;
			if( CH_BREAK == rString.GetChar( nNew ) )
			{
				++nNew;
				rLine.Next();
				bPrev = sal_False;
			}
		}
		rReformat.Len()  += rReformat.Start() - nNew;
		rReformat.Start() = nNew;
	}

	rRepaint.SetOfst( 0 );
	rRepaint.SetRightOfst( 0 );
	rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() );
	if( pPara->IsMargin() )
		rRepaint.Width( rRepaint.Width() + pPara->GetHangingMargin() );
	rRepaint.Top( rLine.Y() );
	// 6792: Rrand < LRand und Repaint
	if( 0 >= rRepaint.Width() )
		rRepaint.Width(1);
	WidowsAndOrphans aFrmBreak( this, rInf.IsTest() ? 1 : 0 );

	// rLine steht jetzt auf der ersten Zeile, die formatiert werden
	// muss. Das Flag bFirst sorgt dafuer, dass nicht Next() gerufen wird.
	// Das ganze sieht verdreht aus, aber es muss sichergestellt werden,
	// dass bei IsBreakNow rLine auf der Zeile zum stehen kommt, die
	// nicht mehr passt.
	sal_Bool bFirst  = sal_True;
	sal_Bool bFormat = sal_True;

	// 5383: Das CharToLine() kann uns auch in den roten Bereich fuehren.
	// In diesem Fall muessen wir zurueckwandern, bis die Zeile, die
	// nicht mehr passt in rLine eingestellt ist. Ansonsten geht Textmasse
	// verloren, weil der Ofst im Follow falsch eingestellt wird.

    // OD 2004-02-25 #i16128# - method renamed
    sal_Bool bBreak = ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 )
                    && aFrmBreak.IsBreakNowWidAndOrp( rLine );
	if( bBreak )
	{
		sal_Bool bPrevDone = 0 != rLine.Prev();
        // OD 2004-02-25 #i16128# - method renamed
        while( bPrevDone && aFrmBreak.IsBreakNowWidAndOrp(rLine) )
			bPrevDone = 0 != rLine.Prev();
		if( bPrevDone )
		{
			aFrmBreak.SetKeep( sal_False );
			rLine.Next();
		}
		rLine.TruncLines();

		// auf Nummer sicher:
        // OD 2004-02-25 #i16128# - method renamed
        bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine) &&
				  ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 );
	}

 /*	Bedeutung der folgenden Flags:
	Ist das Watch(End/Mid)Hyph-Flag gesetzt, so muss formatiert werden, wenn
	eine Trennung am (Zeilenende/Fly) vorliegt, sofern MaxHyph erreicht ist.
	Das Jump(End/Mid)Flag bedeutet, dass die naechste Zeile, bei der keine
	Trennung (Zeilenende/Fly) vorliegt, formatiert werden muss, da jetzt
	umgebrochen werden koennte, was vorher moeglicherweise durch MaxHyph
	verboten war.
	Watch(End/Mid)Hyph wird gesetzt, wenn die letzte formatierte Zeile eine
	Trennstelle erhalten hat, vorher aber keine hatte,
	Jump(End/Mid)Hyph, wenn eine Trennstelle verschwindet.
 */
	sal_Bool bJumpEndHyph  = sal_False,
		 bWatchEndHyph = sal_False,
		 bJumpMidHyph  = sal_False,
		 bWatchMidHyph = sal_False;

	const SwAttrSet& rAttrSet = GetTxtNode()->GetSwAttrSet();
	sal_Bool bMaxHyph = ( 0 !=
		( rInf.MaxHyph() = rAttrSet.GetHyphenZone().GetMaxHyphens() ) );
	if ( bMaxHyph )
		rLine.InitCntHyph();

    if( IsFollow() && IsFieldFollow() && rLine.GetStart() == GetOfst() )
    {
        const SwLineLayout* pLine;
        {
            SwTxtFrm *pMaster = FindMaster();
            ASSERT( pMaster, "SwTxtFrm::Format: homeless follow" );
            if( !pMaster->HasPara() )
                pMaster->GetFormatted();
            SwTxtSizeInfo aInf( pMaster );
            SwTxtIter aMasterLine( pMaster, &aInf );
            aMasterLine.Bottom();
            pLine = aMasterLine.GetCurr();
        }
        SwLinePortion* pRest =
            rLine.MakeRestPortion( pLine, GetOfst() );
        if( pRest )
            rInf.SetRest( pRest );
        else
            SetFieldFollow( sal_False );
    }

	/* Zum Abbruchkriterium:
	 * Um zu erkennen, dass eine Zeile nicht mehr auf die Seite passt,
	 * muss sie formatiert werden. Dieser Ueberhang wird z.B. in AdjustFollow
	 * wieder entfernt.
	 * Eine weitere Komplikation: wenn wir der Master sind, so muessen
	 * wir die Zeilen durchgehen, da es ja sein kann, dass eine Zeile
	 * vom Follow in den Master rutschen kann.
	 */
	do
	{
		DBG_LOOP;
		if( bFirst )
			bFirst = sal_False;
		else
		{
			if ( bMaxHyph )
			{
				if ( rLine.GetCurr()->IsEndHyph() )
					rLine.CntEndHyph()++;
				else
					rLine.CntEndHyph() = 0;
				if ( rLine.GetCurr()->IsMidHyph() )
					rLine.CntMidHyph()++;
				else
					rLine.CntMidHyph() = 0;
			}
			if( !rLine.Next() )
			{
				if( !bFormat )
                {
            		SwLinePortion* pRest =
    					rLine.MakeRestPortion( rLine.GetCurr(),	rLine.GetEnd() );
            		if( pRest )
			            rInf.SetRest( pRest );
                }
				rLine.Insert( new SwLineLayout() );
				rLine.Next();
				bFormat = sal_True;
			}
		}
		if ( !bFormat && bMaxHyph &&
			  (bWatchEndHyph || bJumpEndHyph || bWatchMidHyph || bJumpMidHyph) )
		{
			if ( rLine.GetCurr()->IsEndHyph() )
			{
				if ( bWatchEndHyph )
					bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() );
			}
			else
			{
				bFormat = bJumpEndHyph;
				bWatchEndHyph = sal_False;
				bJumpEndHyph = sal_False;
			}
			if ( rLine.GetCurr()->IsMidHyph() )
			{
				if ( bWatchMidHyph && !bFormat )
					bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() );
			}
			else
			{
				bFormat = bFormat || bJumpMidHyph;
				bWatchMidHyph = sal_False;
				bJumpMidHyph = sal_False;
			}
		}
		if( bFormat )
		{
			sal_Bool bOldEndHyph = rLine.GetCurr()->IsEndHyph();
			sal_Bool bOldMidHyph = rLine.GetCurr()->IsMidHyph();
			bFormat = FormatLine( rLine, bPrev );
			//9334: Es kann nur ein bPrev geben... (???)
			bPrev = sal_False;
			if ( bMaxHyph )
			{
				if ( rLine.GetCurr()->IsEndHyph() != bOldEndHyph )
				{
					bWatchEndHyph = !bOldEndHyph;
					bJumpEndHyph = bOldEndHyph;
				}
				if ( rLine.GetCurr()->IsMidHyph() != bOldMidHyph )
				{
					bWatchMidHyph = !bOldMidHyph;
					bJumpMidHyph = bOldMidHyph;
				}
			}
		}

		if( !rInf.IsNewLine() )
		{
			if( !bFormat )
				 bFormat = 0 != rInf.GetRest();
			if( rInf.IsStop() || rInf.GetIdx() >= nStrLen )
				break;
			if( !bFormat && ( !bMaxHyph || ( !bWatchEndHyph &&
					!bJumpEndHyph && !bWatchMidHyph && !bJumpMidHyph ) ) )
			{
				if( GetFollow() )
				{
					while( rLine.Next() )
						; //Nothing
					pFreeze = new SwRepaint( rRepaint ); // to minimize painting
				}
				else
					break;
			}
		}
        // OD 2004-02-25 #i16128# - method renamed
        bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine);
	}while( !bBreak );

	if( pFreeze )
	{
		rRepaint = *pFreeze;
		delete pFreeze;
	}

	if( !rLine.IsStop() )
	{
		// Wurde aller Text formatiert und gibt es noch weitere
		// Zeilenobjekte, dann sind diese jetzt ueberfluessig,
		// weil der Text kuerzer geworden ist.
		if( rLine.GetStart() + rLine.GetLength() >= nStrLen &&
			rLine.GetCurr()->GetNext() )
		{
			rLine.TruncLines();
			rLine.SetTruncLines( sal_True );
		}
	}

	if( !rInf.IsTest() )
	{
		// Bei OnceMore lohnt sich kein FormatAdjust
		if( bAdjust || !rLine.GetDropFmt() || !rLine.CalcOnceMore() )
        {
            FormatAdjust( rLine, aFrmBreak, nStrLen, rInf.IsStop() );
        }
		if( rRepaint.HasArea() )
			SetRepaint();
		rLine.SetTruncLines( sal_False );
		if( nOldBottom )                    // Bei "gescollten" Absaetzen wird
		{                                   // noch ueberprueft, ob durch Schrumpfen
			rLine.Bottom();					// das Scrolling ueberfluessig wurde.
			SwTwips nNewBottom = rLine.Y();
			if( nNewBottom < nOldBottom )
				_SetOfst( 0 );
		}
	}
}

/*************************************************************************
 *						SwTxtFrm::Format()
 *************************************************************************/

void SwTxtFrm::FormatOnceMore( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf )
{
    ASSERT( ! IsVertical() || IsSwapped(),
            "A frame is not swapped in SwTxtFrm::FormatOnceMore" );

	SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
	if( !pPara )
		return;

	// ggf gegen pPara
	KSHORT nOld  = ((const SwTxtMargin&)rLine).GetDropHeight();
	sal_Bool bShrink = sal_False,
		 bGrow   = sal_False,
		 bGoOn   = rLine.IsOnceMore();
	sal_uInt8 nGo	 = 0;
	while( bGoOn )
	{
#ifdef DBGTXT
		aDbstream << "OnceMore!" << endl;
#endif
		++nGo;
		rInf.Init();
		rLine.Top();
		if( !rLine.GetDropFmt() )
			rLine.SetOnceMore( sal_False );
		SwCharRange aRange( 0, rInf.GetTxt().Len() );
		*(pPara->GetReformat()) = aRange;
		_Format( rLine, rInf );

		bGoOn = rLine.IsOnceMore();
		if( bGoOn )
		{
			const KSHORT nNew = ((const SwTxtMargin&)rLine).GetDropHeight();
			if( nOld == nNew )
				bGoOn = sal_False;
			else
			{
				if( nOld > nNew )
					bShrink = sal_True;
				else
					bGrow = sal_True;

				if( bShrink == bGrow || 5 < nGo )
					bGoOn = sal_False;

				nOld = nNew;
			}

			// 6107: Wenn was schief ging, muss noch einmal formatiert werden.
			if( !bGoOn )
			{
				rInf.CtorInitTxtFormatInfo( this );
				rLine.CtorInitTxtFormatter( this, &rInf );
				rLine.SetDropLines( 1 );
				rLine.CalcDropHeight( 1 );
                SwCharRange aTmpRange( 0, rInf.GetTxt().Len() );
                *(pPara->GetReformat()) = aTmpRange;
				_Format( rLine, rInf, sal_True );
				// 8047: Wir painten alles...
				SetCompletePaint();
			}
		}
	}
}

/*************************************************************************
 *						SwTxtFrm::_Format()
 *************************************************************************/


void SwTxtFrm::_Format( SwParaPortion *pPara )
{
	const xub_StrLen nStrLen = GetTxt().Len();

	// AMA: Wozu soll das gut sein? Scheint mir zuoft zu einem kompletten
	// Formatieren und Repainten zu fuehren???
//	if ( !(*pPara->GetDelta()) )
//		*(pPara->GetDelta()) = nStrLen;
//	else
	if ( !nStrLen )
	{
		// Leere Zeilen werden nicht lange gequaelt:
		// pPara wird blank geputzt
		// entspricht *pPara = SwParaPortion;
		sal_Bool bMustFit = pPara->IsPrepMustFit();
		pPara->Truncate();
		pPara->FormatReset();
		if( pBlink && pPara->IsBlinking() )
			pBlink->Delete( pPara );

        // delete pSpaceAdd und pKanaComp
        pPara->FinishSpaceAdd();
        pPara->FinishKanaComp();
		pPara->ResetFlags();
		pPara->SetPrepMustFit( bMustFit );
	}

    ASSERT( ! IsSwapped(), "A frame is swapped before _Format" );

    if ( IsVertical() )
        SwapWidthAndHeight();

    SwTxtFormatInfo aInf( this );
	SwTxtFormatter	aLine( this, &aInf );

    // OD 2004-01-15 #110582#
    HideAndShowObjects();

    _Format( aLine, aInf );

	if( aLine.IsOnceMore() )
		FormatOnceMore( aLine, aInf );

    if ( IsVertical() )
        SwapWidthAndHeight();

    ASSERT( ! IsSwapped(), "A frame is swapped after _Format" );

    if( 1 < aLine.GetDropLines() )
	{
		if( SVX_ADJUST_LEFT != aLine.GetAdjust() &&
			SVX_ADJUST_BLOCK != aLine.GetAdjust() )
		{
			aLine.CalcDropAdjust();
			aLine.SetPaintDrop( sal_True );
		}

		if( aLine.IsPaintDrop() )
		{
			aLine.CalcDropRepaint();
			aLine.SetPaintDrop( sal_False );
		}
	}
}

/*************************************************************************
 *						SwTxtFrm::Format()
 *************************************************************************/

/*
 * Format berechnet die Groesse des Textframes und ruft, wenn
 * diese feststeht, Shrink() oder Grow(), um die Framegroesse dem
 * evtl. veraenderten Platzbedarf anzupassen.
 */

void SwTxtFrm::Format( const SwBorderAttrs * )
{
	DBG_LOOP;
#if OSL_DEBUG_LEVEL > 1
	const XubString aXXX = GetTxtNode()->GetTxt();
	const SwTwips nDbgY = Frm().Top();
    (void)nDbgY;
	const SwPageFrm *pDbgPage = FindPageFrm();
	const MSHORT nDbgPageNr = pDbgPage->GetPhyPageNum();
    (void)nDbgPageNr;
	// Um zu gucken, ob es einen Ftn-Bereich gibt.
	const SwFrm *pDbgFtnCont = (const SwFrm*)(FindPageFrm()->FindFtnCont());
    (void)pDbgFtnCont;

#ifdef DBG_UTIL
	// nStopAt laesst sich vom CV bearbeiten.
	static MSHORT nStopAt = 0;
	if( nStopAt == GetFrmId() )
	{
		int i = GetFrmId();
        (void)i;
	}
#endif
#endif

#ifdef DEBUG_FTN
	//Fussnote darf nicht auf einer Seite vor ihrer Referenz stehen.
	if( IsInFtn() )
	{
		const SwFtnFrm *pFtn = (SwFtnFrm*)GetUpper();
		const SwPageFrm *pFtnPage = pFtn->GetRef()->FindPageFrm();
		const MSHORT nFtnPageNr = pFtnPage->GetPhyPageNum();
		if( !IsLocked() )
		{
			if( nFtnPageNr > nDbgPageNr )
			{
				SwTxtFrmLocker aLock(this);
				ASSERT( nFtnPageNr <= nDbgPageNr, "!Ftn steht vor der Referenz." );
				MSHORT i = 0;
			}
		}
	}
#endif

    SWRECTFN( this )

    // --> OD 2008-01-31 #newlistlevelattrs#
    CalcAdditionalFirstLineOffset();
    // <--

    // Vom Berichtsautopiloten oder ueber die BASIC-Schnittstelle kommen
    // gelegentlich TxtFrms mit einer Breite <=0.
    if( (Prt().*fnRect->fnGetWidth)() <= 0 )
    {
        // Wenn MustFit gesetzt ist, schrumpfen wir ggf. auf die Unterkante
        // des Uppers, ansonsten nehmen wir einfach eine Standardgroesse
        // von 12 Pt. ein (240 Twip).
        SwTxtLineAccess aAccess( this );
        long nFrmHeight = (Frm().*fnRect->fnGetHeight)();
        if( aAccess.GetPara()->IsPrepMustFit() )
        {
            const SwTwips nLimit = (GetUpper()->*fnRect->fnGetPrtBottom)();
            const SwTwips nDiff = - (Frm().*fnRect->fnBottomDist)( nLimit );
            if( nDiff > 0 )
                Shrink( nDiff );
        }
        else if( 240 < nFrmHeight )
            Shrink( nFrmHeight - 240 );
        else if( 240 > nFrmHeight )
            Grow( 240 - nFrmHeight );
        nFrmHeight = (Frm().*fnRect->fnGetHeight)();

        long nTop = (this->*fnRect->fnGetTopMargin)();
        if( nTop > nFrmHeight )
            (this->*fnRect->fnSetYMargins)( nFrmHeight, 0 );
        else if( (Prt().*fnRect->fnGetHeight)() < 0 )
            (Prt().*fnRect->fnSetHeight)( 0 );
        return;
    }

    const xub_StrLen nStrLen = GetTxtNode()->GetTxt().Len();
    if ( nStrLen || !FormatEmpty() )
    {

        SetEmpty( sal_False );
        // Um nicht durch verschachtelte Formats irritiert zu werden.
        FormatLevel aLevel;
        if( 12 == aLevel.GetLevel() )
            return;

        // Die Formatinformationen duerfen u.U. nicht veraendert werden.
        if( IsLocked() )
            return;

        // 8708: Vorsicht, das Format() kann auch durch GetFormatted()
        // angestossen werden.
        if( IsHiddenNow() )
        {
            long nPrtHeight = (Prt().*fnRect->fnGetHeight)();
            if( nPrtHeight )
            {
                HideHidden();
                Shrink( nPrtHeight );
            }
            else
            {
                // OD 2004-01-20 #110582# - assure that objects anchored
                // at paragraph resp. at/as character inside paragraph
                // are hidden.
                HideAndShowObjects();
            }
            ChgThisLines();
            return;
        }

        // Waehrend wir formatieren, wollen wir nicht gestoert werden.
        SwTxtFrmLocker aLock(this);
        SwTxtLineAccess aAccess( this );
        const sal_Bool bNew = !aAccess.SwTxtLineAccess::IsAvailable();
        const sal_Bool bSetOfst = ( GetOfst() && GetOfst() > GetTxtNode()->GetTxt().Len() );

        if( CalcPreps() )
            ; // nothing
        // Wir returnen, wenn schon formatiert wurde, nicht aber, wenn
        // der TxtFrm gerade erzeugt wurde und ueberhaupt keine Format-
        // informationen vorliegen.
        else if( !bNew && !aAccess.GetPara()->GetReformat()->Len() )
        {
            if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() )
            {
                aAccess.GetPara()->SetPrepAdjust( sal_True );
                aAccess.GetPara()->SetPrep( sal_True );
                CalcPreps();
            }
            SetWidow( sal_False );
        }
        else if( bSetOfst && IsFollow() )
        {
            SwTxtFrm *pMaster = FindMaster();
            ASSERT( pMaster, "SwTxtFrm::Format: homeless follow" );
            if( pMaster )
                pMaster->Prepare( PREP_FOLLOW_FOLLOWS );
            SwTwips nMaxY = (GetUpper()->*fnRect->fnGetPrtBottom)();
            if( (Frm().*fnRect->fnOverStep)( nMaxY  ) )
                (this->*fnRect->fnSetLimit)( nMaxY );
            else if( (Frm().*fnRect->fnBottomDist)( nMaxY  ) < 0 )
                (Frm().*fnRect->fnAddBottom)( -(Frm().*fnRect->fnGetHeight)() );
        }
        else
        {
            // bSetOfst here means that we have the "red arrow situation"
            if ( bSetOfst )
                _SetOfst( 0 );

            const sal_Bool bOrphan = IsWidow();
            const SwFtnBossFrm* pFtnBoss = HasFtn() ? FindFtnBossFrm() : 0;
            SwTwips nFtnHeight = 0;
            if( pFtnBoss )
            {
                const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont();
                nFtnHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0;
            }
            do
            {
                _Format( aAccess.GetPara() );
                if( pFtnBoss && nFtnHeight )
                {
                    const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont();
                    SwTwips nNewHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0;
                    // If we lost some footnotes, we may have more space
                    // for our main text, so we have to format again ...
                    if( nNewHeight < nFtnHeight )
                        nFtnHeight = nNewHeight;
                    else
                        break;
                }
                else
                    break;
            } while ( pFtnBoss );
            if( bOrphan )
            {
                ValidateFrm();
                SetWidow( sal_False );
            }
        }
        if( IsEmptyMaster() )
        {
            SwFrm* pPre = GetPrev();
            if( pPre &&
                // --> FME 2004-07-22 #i10826# It's the first, it cannot keep!
                pPre->GetIndPrev() &&
                // <--
                pPre->GetAttrSet()->GetKeep().GetValue() )
            {
                pPre->InvalidatePos();
            }
        }
    }

	ChgThisLines();

    // the PrepMustFit should not survive a Format operation
    SwParaPortion *pPara = GetPara();
	if ( pPara )
       	pPara->SetPrepMustFit( sal_False );

#if OSL_DEBUG_LEVEL > 1
	// Hier ein Instrumentarium, um ungewoehnlichen Master/Follow-Kombinationen,
	// insbesondere bei Fussnoten, auf die Schliche zu kommen
	if( IsFollow() || GetFollow() )
	{
		SwTxtFrm *pTmpFrm = IsFollow() ? FindMaster() : this;
		const SwPageFrm *pTmpPage = pTmpFrm->FindPageFrm();
		MSHORT nPgNr = pTmpPage->GetPhyPageNum();
		MSHORT nLast;
		MSHORT nDummy = 0; // nur zum Breakpoint setzen
		while( pTmpFrm->GetFollow() )
		{
			pTmpFrm = pTmpFrm->GetFollow();
			nLast = nPgNr;
			pTmpPage = pTmpFrm->FindPageFrm();
			nPgNr = pTmpPage->GetPhyPageNum();
			if( nLast > nPgNr )
				++nDummy; // schon fast eine Assertion wert
			else if( nLast == nPgNr )
				++nDummy; // bei Spalten voellig normal, aber sonst!?
			else if( nLast < nPgNr - 1 )
				++nDummy; // kann schon mal temporaer vorkommen
		}
	}
#endif

    CalcBaseOfstForFly();
    // OD 2004-03-17 #i11860#
    _CalcHeightOfLastLine();
}

/*************************************************************************
 *						SwTxtFrm::FormatQuick()
 *
 * bForceQuickFormat is set if GetFormatted() has been called during the
 * painting process. Actually I cannot imagine a situation which requires
 * a full formatting of the paragraph during painting, on the other hand
 * a full formatting can cause the invalidation of other layout frames,
 * e.g., if there are footnotes in this paragraph, and invalid layout
 * frames will not calculated during the painting. So I actually want to
 * avoid a formatting during painting, but since I'm a coward, I'll only
 * force the quick formatting in the situation of issue i29062.
 *************************************************************************/

sal_Bool SwTxtFrm::FormatQuick( bool bForceQuickFormat )
{
    ASSERT( ! IsVertical() || ! IsSwapped(),
            "SwTxtFrm::FormatQuick with swapped frame" );

	DBG_LOOP;
#if OSL_DEBUG_LEVEL > 1
	const XubString aXXX = GetTxtNode()->GetTxt();
	const SwTwips nDbgY = Frm().Top();
    (void)nDbgY;
#ifdef DBG_UTIL
	// nStopAt laesst sich vom CV bearbeiten.
	static MSHORT nStopAt = 0;
	if( nStopAt == GetFrmId() )
	{
		int i = GetFrmId();
        (void)i;
	}
#endif
#endif

	if( IsEmpty() && FormatEmpty() )
		return sal_True;

    // Wir sind sehr waehlerisch:
	if( HasPara() || IsWidow() || IsLocked()
        || !GetValidSizeFlag() ||
        ( ( IsVertical() ? Prt().Width() : Prt().Height() ) && IsHiddenNow() ) )
		return sal_False;

	SwTxtLineAccess aAccess( this );
	SwParaPortion *pPara = aAccess.GetPara();
	if( !pPara )
		return sal_False;

    SwFrmSwapper aSwapper( this, sal_True );

    SwTxtFrmLocker aLock(this);
	SwTxtFormatInfo aInf( this, sal_False, sal_True );
	if( 0 != aInf.MaxHyph() )	// 27483: MaxHyphen beachten!
		return sal_False;

	SwTxtFormatter	aLine( this, &aInf );

	// DropCaps sind zu kompliziert...
	if( aLine.GetDropFmt() )
        return sal_False;

	xub_StrLen nStart = GetOfst();
	const xub_StrLen nEnd = GetFollow()
					  ? GetFollow()->GetOfst() : aInf.GetTxt().Len();
	do
    {
        //DBG_LOOP; shadows declaration above.
		//resolved into:
#if OSL_DEBUG_LEVEL > 1
#ifdef DBG_UTIL
		DbgLoop aDbgLoop2( (const void*) this );
#endif
#endif
		nStart = aLine.FormatLine( nStart );
		if( aInf.IsNewLine() || (!aInf.IsStop() && nStart < nEnd) )
			aLine.Insert( new SwLineLayout() );
	} while( aLine.Next() );

    // Last exit: die Hoehen muessen uebereinstimmen.
	Point aTopLeft( Frm().Pos() );
	aTopLeft += Prt().Pos();
	const SwTwips nNewHeight = aLine.Y() + aLine.GetLineHeight();
	const SwTwips nOldHeight = aTopLeft.Y() + Prt().Height();

    if( !bForceQuickFormat && nNewHeight != nOldHeight && !IsUndersized() )
	{
        // Achtung: Durch FormatLevel==12 kann diese Situation auftreten, don't panic!
        // ASSERT( nNewHeight == nOldHeight, "!FormatQuick: rosebud" );
        const xub_StrLen nStrt = GetOfst();
		_InvalidateRange( SwCharRange( nStrt, nEnd - nStrt) );
		return sal_False;
	}

	if( pFollow && nStart != ((SwTxtFrm*)pFollow)->GetOfst() )
		return sal_False; // kann z.B. durch Orphans auftreten (35083,35081)

	// Geschafft, wir sind durch ...

	// Repaint setzen
	pPara->GetRepaint()->Pos( aTopLeft );
	pPara->GetRepaint()->SSize( Prt().SSize() );

	// Reformat loeschen
	*(pPara->GetReformat()) = SwCharRange();
	*(pPara->GetDelta()) = 0;

	return sal_True;
}
