/**************************************************************
 * 
 * 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 <vcl/outdev.hxx>
#include <vcl/virdev.hxx>

#include "viewsh.hxx"
#include "pagefrm.hxx"
#include "rootfrm.hxx"
#include "viewimp.hxx"		// SwViewImp
#include "pam.hxx"			// SwPosition
#include "swregion.hxx"		// SwRegionRects
#include "dcontact.hxx"		// SwContact
#include "dflyobj.hxx"		// SdrObject
#include "flyfrm.hxx"	  // SwFlyFrm
#include "frmtool.hxx"	  // ::DrawGraphic
#include "porfld.hxx"		// SwGrfNumPortion
#include "txtfrm.hxx"     // SwTxtFrm
#include "itrform2.hxx"   // SwTxtFormatter
#include "porfly.hxx"     // NewFlyCntPortion
#include "porfld.hxx"     // SwGrfNumPortion
#include "txtfly.hxx"     // SwTxtFly
#include "txtpaint.hxx"   // SwSaveClip
#include "txtatr.hxx"     // SwTxtFlyCnt
#include "txtcfg.hxx"
#include "notxtfrm.hxx"
#include "flyfrms.hxx"
#include "fmtcnct.hxx"  // SwFmtChain
#include <pormulti.hxx> 	// SwMultiPortion
#include <svx/obj3d.hxx>
#include <editeng/txtrange.hxx>
#include <editeng/lrspitem.hxx>
#include <editeng/ulspitem.hxx>
// --> OD 2004-06-16 #i28701#
#include <editeng/lspcitem.hxx>
// <--
#include <txtflcnt.hxx>
#include <fmtsrnd.hxx>
#include <fmtanchr.hxx>
#include <fmtflcnt.hxx>
#include <frmfmt.hxx>
#include <pagedesc.hxx> // SwPageDesc
#include <tgrditem.hxx>
#include <sortedobjs.hxx>
#include <layouter.hxx>
#include <IDocumentDrawModelAccess.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <IDocumentSettingAccess.hxx>
#include <svx/obj3d.hxx>
#include <editeng/txtrange.hxx>
#include <editeng/lrspitem.hxx>
#include <editeng/ulspitem.hxx>
#include <editeng/lspcitem.hxx>
#include <svx/svdoedge.hxx>
#include "doc.hxx"

#ifdef DBG_UTIL
#include "viewopt.hxx"	// SwViewOptions, nur zum Testen (Test2)
#include "doc.hxx"
#endif

#ifdef VERT_DISTANCE
#include <math.h>
#endif


using namespace ::com::sun::star;

/*****************************************************************************
 * Beschreibung:
 * Die Klasse SwTxtFly soll die Universalschnittstelle zwischen der
 * Formatierung/Textausgabe und den u.U. ueberlappenden freifliegenden
 * Frames sein.
 * Waehrend der Formatierung erkundigt sich der Formatierer beim SwTxtFly,
 * ob ein bestimmter Bereich durch die Attribute eines ueberlappenden
 * Frames vorliegt. Solche Bereiche werden in Form von Dummy-Portions
 * abgebildet.
 * Die gesamte Textausgabe und Retusche wird ebenfalls an ein SwTxtFly
 * weitergeleitet. Dieser entscheidet, ob Textteile geclippt werden muessen
 * und zerteilt z.B. die Bereiche bei einem DrawRect.
 * Zu beachten ist, dass alle freifliegenden Frames in einem nach TopLeft
 * sortiertem PtrArray an der Seite zu finden sind. Intern wird immer nur
 * in dokumentglobalen Werten gerechnet. Die IN- und OUT-Parameter sind
 * jedoch in den meisten Faellen an die Beduerfnisse des LineIters
 * zugeschnitten, d.h. sie werden in frame- oder windowlokalen Koordinaten
 * konvertiert.
 * Wenn mehrere Frames mit Umlaufattributen in einer Zeile liegen,
 * ergeben sich unterschiedliche Auswirkungen fuer den Textfluss:
 *
 *		L/R    P	 L	   R	 K
 *		 P	 -P-P- -P-L  -P R- -P K
 *		 L	 -L P- -L L  -L R- -L K
 *		 R	  R-P-	R-L   R R-	R K
 *		 K	  K P-	K L   K R-	K K
 *
 * (P=parallel, L=links, R=rechts, K=kein Umlauf)
 *
 * Das Verhalten so beschreiben:
 * Jeder Rahmen kann Text verdraengen, wobei der Einfluss allerdings nur
 * bis zum naechsten Rahmen reicht.
 *****************************************************************************/

void SwTxtFormatter::CalcUnclipped( SwTwips& rTop, SwTwips& rBottom )
{
    ASSERT( ! pFrm->IsVertical() || pFrm->IsSwapped(),
            "SwTxtFormatter::CalcUnclipped with unswapped frame" )

	long nFlyAsc, nFlyDesc;
    // OD 08.01.2004 #i11859# - use new method <SwLineLayout::MaxAscentDescent(..)>
    //lcl_MaxAscDescent( pCurr, rTop, rBottom, nFlyAsc, nFlyDesc );
    pCurr->MaxAscentDescent( rTop, rBottom, nFlyAsc, nFlyDesc );
	rTop = Y() + GetCurr()->GetAscent();
	rBottom = rTop + nFlyDesc;
	rTop -= nFlyAsc;
}

/*************************************************************************
 * SwTxtFormatter::UpdatePos() aktualisiert die Referenzpunkte der zeichengeb.
 * Objekte, z. B. nach Adjustierung ( rechtsbuendig, Blocksatz etc. )
 * ( hauptsaechlich Korrrektur der X-Position )
 *************************************************************************/

void SwTxtFormatter::UpdatePos( SwLineLayout *pCurrent, Point aStart,
	xub_StrLen nStartIdx, sal_Bool bAllWays ) const
{
    ASSERT( ! pFrm->IsVertical() || pFrm->IsSwapped(),
            "SwTxtFormatter::UpdatePos with unswapped frame" )

    if( GetInfo().IsTest() )
		return;
    SwLinePortion *pFirst = pCurrent->GetFirstPortion();
    SwLinePortion *pPos = pFirst;
	SwTxtPaintInfo aTmpInf( GetInfo() );
    aTmpInf.SetpSpaceAdd( pCurrent->GetpLLSpaceAdd() );
	aTmpInf.ResetSpaceIdx();
    aTmpInf.SetKanaComp( pCurrent->GetpKanaComp() );
    aTmpInf.ResetKanaIdx();

	// Die Groesse des Frames
	aTmpInf.SetIdx( nStartIdx );
	aTmpInf.SetPos( aStart );

	long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;
    // OD 08.01.2004 #i11859# - use new method <SwLineLayout::MaxAscentDescent(..)>
    //lcl_MaxAscDescent( pPos, nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
    pCurrent->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );

    KSHORT nTmpHeight = pCurrent->GetRealHeight();
    KSHORT nAscent = pCurrent->GetAscent() + nTmpHeight - pCurrent->Height();
    objectpositioning::AsCharFlags nFlags = AS_CHAR_ULSPACE;
	if( GetMulti() )
	{
		aTmpInf.SetDirection( GetMulti()->GetDirection() );
		if( GetMulti()->HasRotation() )
		{
            nFlags |= AS_CHAR_ROTATE;
			if( GetMulti()->IsRevers() )
			{
                nFlags |= AS_CHAR_REVERSE;
				aTmpInf.X( aTmpInf.X() - nAscent );
			}
			else
				aTmpInf.X( aTmpInf.X() + nAscent );
		}
        else
        {
            if ( GetMulti()->IsBidi() )
                nFlags |= AS_CHAR_BIDI;
			aTmpInf.Y( aTmpInf.Y() + nAscent );
        }
	}
	else
		aTmpInf.Y( aTmpInf.Y() + nAscent );

	while( pPos )
	{
		// bislang ist mir nur ein Fall bekannt, wo die Positionsaenderung
		// (verursacht durch das Adjustment) fuer eine Portion wichtig
		// sein koennte: Bei FlyCntPortions muss ein SetRefPoint erfolgen.
		if( ( pPos->IsFlyCntPortion() || pPos->IsGrfNumPortion() )
			&& ( bAllWays || !IsQuick() ) )
		{
            // OD 08.01.2004 #i11859# - use new method <SwLineLayout::MaxAscentDescent(..)>
            //lcl_MaxAscDescent( pFirst, nTmpAscent, nTmpDescent,
            //                  nFlyAsc, nFlyDesc, pPos );
            pCurrent->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, pPos );

			if( pPos->IsGrfNumPortion() )
			{
				if( !nFlyAsc && !nFlyDesc )
				{
					nTmpAscent = nAscent;
					nFlyAsc = nAscent;
					nTmpDescent = nTmpHeight - nAscent;
					nFlyDesc = nTmpDescent;
				}
				((SwGrfNumPortion*)pPos)->SetBase( nTmpAscent, nTmpDescent,
												   nFlyAsc, nFlyDesc );
			}
			else
			{
                Point aBase( aTmpInf.GetPos() );
                if ( GetInfo().GetTxtFrm()->IsVertical() )
                    GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( aBase );

                ((SwFlyCntPortion*)pPos)->SetBase( *aTmpInf.GetTxtFrm(),
                    aBase, nTmpAscent, nTmpDescent, nFlyAsc,
                    nFlyDesc, nFlags );
			}
		}
		if( pPos->IsMultiPortion() && ((SwMultiPortion*)pPos)->HasFlyInCntnt() )
		{
			ASSERT( !GetMulti(), "Too much multi" );
			((SwTxtFormatter*)this)->pMulti = (SwMultiPortion*)pPos;
			SwLineLayout *pLay = &GetMulti()->GetRoot();
            Point aSt( aTmpInf.X(), aStart.Y() );

            if ( GetMulti()->HasBrackets() )
            {
                ASSERT( GetMulti()->IsDouble(), "Brackets only for doubles");
                aSt.X() += ((SwDoubleLinePortion*)GetMulti())->PreWidth();
            }
            else if( GetMulti()->HasRotation() )
			{
                aSt.Y() += pCurrent->GetAscent() - GetMulti()->GetAscent();
                if( GetMulti()->IsRevers() )
                    aSt.X() += GetMulti()->Width();
                else
					aSt.Y() += GetMulti()->Height();
	   		}
            else if ( GetMulti()->IsBidi() )
                // jump to end of the bidi portion
                aSt.X() += pLay->Width();

            xub_StrLen nStIdx = aTmpInf.GetIdx();
			do
			{
				UpdatePos( pLay, aSt, nStIdx, bAllWays );
				nStIdx = nStIdx + pLay->GetLen();
				aSt.Y() += pLay->Height();
				pLay = pLay->GetNext();
			} while ( pLay );
			((SwTxtFormatter*)this)->pMulti = NULL;
		}
		pPos->Move( aTmpInf );
		pPos = pPos->GetPortion();
	}
}

/*************************************************************************
 * SwTxtFormatter::AlignFlyInCntBase()
 * richtet die zeichengeb. Objekte in Y-Richtung ggf. neu aus.
 *************************************************************************/

void SwTxtFormatter::AlignFlyInCntBase( long nBaseLine ) const
{
    ASSERT( ! pFrm->IsVertical() || pFrm->IsSwapped(),
            "SwTxtFormatter::AlignFlyInCntBase with unswapped frame" )

	if( GetInfo().IsTest() )
		return;
	SwLinePortion *pFirst = pCurr->GetFirstPortion();
	SwLinePortion *pPos = pFirst;
    objectpositioning::AsCharFlags nFlags = AS_CHAR_NOFLAG;
	if( GetMulti() && GetMulti()->HasRotation() )
	{
        nFlags |= AS_CHAR_ROTATE;
		if( GetMulti()->IsRevers() )
            nFlags |= AS_CHAR_REVERSE;
	}

	long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;

	while( pPos )
	{
		if( pPos->IsFlyCntPortion() || pPos->IsGrfNumPortion() )
		{
            // OD 08.01.2004 #i11859# - use new method <SwLineLayout::MaxAscentDescent(..)>
            //lcl_MaxAscDescent( pFirst, nTmpAscent, nTmpDescent,
            //                  nFlyAsc, nFlyDesc, pPos );
            pCurr->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, pPos );

			if( pPos->IsGrfNumPortion() )
				((SwGrfNumPortion*)pPos)->SetBase( nTmpAscent, nTmpDescent,
												   nFlyAsc, nFlyDesc );
			else
			{
                Point aBase;
                if ( GetInfo().GetTxtFrm()->IsVertical() )
                {
                    nBaseLine = GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( nBaseLine );
                    aBase = Point( nBaseLine, ((SwFlyCntPortion*)pPos)->GetRefPoint().Y() );
                }
                else
                    aBase = Point( ((SwFlyCntPortion*)pPos)->GetRefPoint().X(), nBaseLine );

                ((SwFlyCntPortion*)pPos)->SetBase( *GetInfo().GetTxtFrm(), aBase, nTmpAscent, nTmpDescent,
					nFlyAsc, nFlyDesc, nFlags );
			}
		}
		pPos = pPos->GetPortion();
	}
}

/*************************************************************************
 *                      SwTxtFly::ChkFlyUnderflow()
 * This is called after the real height of the line has been calculated
 * Therefore it is possible, that more flys from below intersect with the
 * line, or that flys from above do not intersect with the line anymore
 * We check this and return true if so, meaning that the line has to be
 * formatted again
 *************************************************************************/

sal_Bool SwTxtFormatter::ChkFlyUnderflow( SwTxtFormatInfo &rInf ) const
{
    ASSERT( rInf.GetTxtFly()->IsOn(), "SwTxtFormatter::ChkFlyUnderflow: why?" );
	if( GetCurr() )
	{
		// Erst pruefen wir, ob ueberhaupt ein Fly mit der Zeile ueberlappt.
        // = GetLineHeight()
        const long nHeight = GetCurr()->GetRealHeight();
		SwRect aLine( GetLeftMargin(), Y(), rInf.RealWidth(), nHeight );

        SwRect aLineVert( aLine );
        if ( pFrm->IsVertical() )
            pFrm->SwitchHorizontalToVertical( aLineVert );
        SwRect aInter( rInf.GetTxtFly()->GetFrm( aLineVert ) );
        if ( pFrm->IsVertical() )
            pFrm->SwitchVerticalToHorizontal( aInter );

		if( !aInter.HasArea() )
			return sal_False;

		// Nun ueberpruefen wir jede Portion, die sich haette senken koennen,
		// ob sie mit dem Fly ueberlappt.
		const SwLinePortion *pPos = GetCurr()->GetFirstPortion();
        aLine.Pos().Y() = Y() + GetCurr()->GetRealHeight() - GetCurr()->Height();
        aLine.Height( GetCurr()->Height() );

		while( pPos )
		{
            aLine.Width( pPos->Width() );

            aLineVert = aLine;
            if ( pFrm->IsVertical() )
                pFrm->SwitchHorizontalToVertical( aLineVert );
            aInter = rInf.GetTxtFly()->GetFrm( aLineVert );
            if ( pFrm->IsVertical() )
                pFrm->SwitchVerticalToHorizontal( aInter );

            // new flys from below?
			if( !pPos->IsFlyPortion() )
			{
				if( aInter.IsOver( aLine ) )
				{
					aInter._Intersection( aLine );
					if( aInter.HasArea() )
					{
                        // to be evaluated during reformat of this line:
                        // RealHeight including spacing
						rInf.SetLineHeight( KSHORT(nHeight) );
                        // Height without extra spacing
                        rInf.SetLineNettoHeight( KSHORT( pCurr->Height() ) );
						return sal_True;
					}
				}
			}
            else
            {
                // the fly portion is not anylonger intersected by a fly
                if ( ! aInter.IsOver( aLine ) )
                {
                    rInf.SetLineHeight( KSHORT(nHeight) );
                    rInf.SetLineNettoHeight( KSHORT( pCurr->Height() ) );
                    return sal_True;
                }
                else
                {
					aInter._Intersection( aLine );

                    // no area means a fly has become invalid because of
                    // lowering the line => reformat the line
                    // we also have to reformat the line, if the fly size
                    // differs from the intersection intervals size
                    if( ! aInter.HasArea() ||
                        ((SwFlyPortion*)pPos)->GetFixWidth() != aInter.Width() )
					{
						rInf.SetLineHeight( KSHORT(nHeight) );
                        rInf.SetLineNettoHeight( KSHORT( pCurr->Height() ) );
						return sal_True;
					}
				}
            }

			aLine.Left( aLine.Left() + pPos->Width() );
			pPos = pPos->GetPortion();
		}
	}
	return sal_False;
}

/*************************************************************************
 * SwTxtFormatter::CalcFlyWidth()
 * ermittelt das naechste Objekt, das in die restliche Zeile ragt und
 * konstruiert die zugehoerige FlyPortion.
 * Dazu wird SwTxtFly.GetFrm(..) benutzt.
 *************************************************************************/

// Durch Flys kann sich der rechte Rand verkuerzen.

void SwTxtFormatter::CalcFlyWidth( SwTxtFormatInfo &rInf )
{
    if( GetMulti() || rInf.GetFly() )
		return;

	SwTxtFly *pTxtFly = rInf.GetTxtFly();
	if( !pTxtFly->IsOn() || rInf.IsIgnoreFly() )
		return;

	const SwLinePortion *pLast = rInf.GetLast();

	long nAscent;
    long nTop = Y();
    long nHeight;

    if( rInf.GetLineHeight() )
    {
        // real line height has already been calculated, we only have to
        // search for intersections in the lower part of the strip
        nAscent = pCurr->GetAscent();
        nHeight = rInf.GetLineNettoHeight();
        nTop += rInf.GetLineHeight() - nHeight;
	}
	else
	{
        nAscent = pLast->GetAscent();
        nHeight = pLast->Height();

        // we make a first guess for the lines real height
        if ( ! pCurr->GetRealHeight() )
            CalcRealHeight();

        if ( pCurr->GetRealHeight() > nHeight )
            nTop += pCurr->GetRealHeight() - nHeight;
        else
            // important for fixed space between lines
            nHeight = pCurr->GetRealHeight();
	}

    const long nLeftMar = GetLeftMargin();
    const long nLeftMin = (rInf.X() || GetDropLeft()) ? nLeftMar : GetLeftMin();

    SwRect aLine( rInf.X() + nLeftMin, nTop, rInf.RealWidth() - rInf.X()
				  + nLeftMar - nLeftMin	, nHeight );

    SwRect aLineVert( aLine );
    if ( pFrm->IsRightToLeft() )
        pFrm->SwitchLTRtoRTL( aLineVert );

    if ( pFrm->IsVertical() )
        pFrm->SwitchHorizontalToVertical( aLineVert );
    SwRect aInter( pTxtFly->GetFrm( aLineVert ) );

    if ( pFrm->IsRightToLeft() )
        pFrm->SwitchRTLtoLTR( aInter );

    if ( pFrm->IsVertical() )
        pFrm->SwitchVerticalToHorizontal( aInter );

    if( aInter.IsOver( aLine ) )
	{
        aLine.Left( rInf.X() + nLeftMar );
		sal_Bool bForced = sal_False;
		if( aInter.Left() <= nLeftMin )
		{
			SwTwips nFrmLeft = GetTxtFrm()->Frm().Left();
			if( GetTxtFrm()->Prt().Left() < 0 )
				nFrmLeft += GetTxtFrm()->Prt().Left();
			if( aInter.Left() < nFrmLeft )
				aInter.Left( nFrmLeft );

            long nAddMar = 0;
            if ( pFrm->IsRightToLeft() )
            {
                nAddMar = pFrm->Frm().Right() - Right();
                if ( nAddMar < 0 )
                    nAddMar = 0;
            }
            else
                nAddMar = nLeftMar - nFrmLeft;

            aInter.Width( aInter.Width() + nAddMar );
			// Bei negativem Erstzeileneinzug setzen wir das Flag,
			// um anzuzeigen, dass der Einzug/Rand verschoben wurde
			// Dies muss beim DefaultTab an der Nullposition beruecksichtigt
			// werden.
			if( IsFirstTxtLine() && HasNegFirst() )
				bForced = sal_True;
		}
		aInter.Intersection( aLine );
		if( !aInter.HasArea() )
			return;

		const sal_Bool bFullLine =	aLine.Left()  == aInter.Left() &&
								aLine.Right() == aInter.Right();

		// Obwohl kein Text mehr da ist, muss eine weitere Zeile
		// formatiert werden, weil auch leere Zeilen einem Fly
		// ohne Umlauf ausweichen muessen.
		if( bFullLine && rInf.GetIdx() == rInf.GetTxt().Len() )
		{
			rInf.SetNewLine( sal_True );
			// 8221: Dummies erkennt man an Ascent == Height
            pCurr->SetDummy(sal_True);
		}

		// aInter wird framelokal
		aInter.Pos().X() -= nLeftMar;
		SwFlyPortion *pFly = new SwFlyPortion( aInter );
		if( bForced )
		{
			pCurr->SetForcedLeftMargin( sal_True );
            rInf.ForcedLeftMargin( (sal_uInt16)aInter.Width() );
		}

		if( bFullLine )
		{
			// 8110: wir muessen um Einheiten von Zeilenhoehen anwachsen,
			// um nebeneinanderliegende Flys mit unterschiedlichen
			// Umlaufattributen angemessen zu umfliessen.
			// Die letzte ausweichende Zeile, sollte in der Hoehe angepasst
			// sein, damit nicht der Eindruck von "Rahmenabstaenden" aufkommt.
			// 8221: Wichtig ist, dass Ascent == Height ist, weil die FlyPortionWerte
			// im CalcLine in pCurr uebertragen werden und IsDummy() darauf
			// angewiesen ist.
			// Es gibt meines Wissens nur zwei Stellen, in denen DummyLines
			// entstehen koennen: hier und in MakeFlyDummies.
			// Ausgewertet wird IsDummy() in IsFirstTxtLine() und
			// beim Zeilenwandern und im Zusammenhang mit DropCaps.
			pFly->Height( KSHORT(aInter.Height()) );

			// In nNextTop steckt jetzt die Unterkante des Rahmens, dem wir
			// ausweichen oder die Oberkante des naechsten Rahmens, den wir
			// beachten muessen. Wir koennen also jetzt getrost bis zu diesem
			// Wert anwachsen, so sparen wir einige Leerzeilen.
            long nNextTop = pTxtFly->GetNextTop();
            if ( pFrm->IsVertical() )
                nNextTop = pFrm->SwitchVerticalToHorizontal( nNextTop );
            if( nNextTop > aInter.Bottom() )
			{
                SwTwips nH = nNextTop - aInter.Top();
				if( nH < KSHRT_MAX )
					pFly->Height( KSHORT( nH ) );
			}
			if( nAscent < pFly->Height() )
				pFly->SetAscent( KSHORT(nAscent) );
			else
				pFly->SetAscent( pFly->Height() );
		}
		else
		{
			if( rInf.GetIdx() == rInf.GetTxt().Len() )
			{
				// Nicht nHeight nehmen, sonst haben wir einen Riesendescent
				pFly->Height( pLast->Height() );
				pFly->SetAscent( pLast->GetAscent() );
			}
			else
			{
				pFly->Height( KSHORT(aInter.Height()) );
				if( nAscent < pFly->Height() )
					pFly->SetAscent( KSHORT(nAscent) );
				else
					pFly->SetAscent( pFly->Height() );
			}
		}

		rInf.SetFly( pFly );

        if( pFly->Fix() < rInf.Width() )
			rInf.Width( pFly->Fix() );

        GETGRID( pFrm->FindPageFrm() )
        if ( pGrid )
        {
            const SwPageFrm* pPageFrm = pFrm->FindPageFrm();
            const SwLayoutFrm* pBody = pPageFrm->FindBodyCont();

            SWRECTFN( pPageFrm )

            const long nGridOrigin = pBody ?
                                    (pBody->*fnRect->fnGetPrtLeft)() :
                                    (pPageFrm->*fnRect->fnGetPrtLeft)();

			const SwDoc *pDoc = rInf.GetTxtFrm()->GetNode()->GetDoc();
            const sal_uInt16 nGridWidth = GETGRIDWIDTH( pGrid, pDoc);	//for textgrid refactor

            SwTwips nStartX = GetLeftMargin();
            if ( bVert )
            {
                Point aPoint( nStartX, 0 );
                pFrm->SwitchHorizontalToVertical( aPoint );
                nStartX = aPoint.Y();
            }

            const SwTwips nOfst = nStartX - nGridOrigin;
            const SwTwips nTmpWidth = rInf.Width() + nOfst;

            const sal_uLong i = nTmpWidth / nGridWidth + 1;

            const long nNewWidth = ( i - 1 ) * nGridWidth - nOfst;
            if ( nNewWidth > 0 )
                rInf.Width( (sal_uInt16)nNewWidth );
            else
                rInf.Width( 0 );
        }
	}
}

/*****************************************************************************
 * SwTxtFormatter::NewFlyCntPortion
 * legt eine neue Portion fuer ein zeichengebundenes Objekt an.
 *****************************************************************************/

SwFlyCntPortion *SwTxtFormatter::NewFlyCntPortion( SwTxtFormatInfo &rInf,
												   SwTxtAttr *pHint ) const
{
	SwFlyCntPortion *pRet = 0;
	const SwFrm *pFrame = (SwFrm*)pFrm;

	SwFlyInCntFrm *pFly;
	SwFrmFmt* pFrmFmt = ((SwTxtFlyCnt*)pHint)->GetFlyCnt().GetFrmFmt();
	if( RES_FLYFRMFMT == pFrmFmt->Which() )
		pFly = ((SwTxtFlyCnt*)pHint)->GetFlyFrm(pFrame);
	else
		pFly = NULL;
	// aBase bezeichnet die dokumentglobale Position,
	// ab der die neue Extraportion plaziert wird.
	// aBase.X() = Offset in der Zeile,
	//			   hinter der aktuellen Portion
	// aBase.Y() = LineIter.Y() + Ascent der aktuellen Portion

	long nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc;
    // OD 08.01.2004 #i11859# - use new method <SwLineLayout::MaxAscentDescent(..)>
    //SwLinePortion *pPos = pCurr->GetFirstPortion();
    //lcl_MaxAscDescent( pPos, nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );
    pCurr->MaxAscentDescent( nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc );

	// Wenn der Ascent des Rahmens groesser als der Ascent der akt. Portion
	// ist, wird dieser bei der Base-Berechnung verwendet, sonst wuerde
	// der Rahmen zunaechst zu weit nach oben gesetzt, um dann doch wieder
	// nach unten zu rutschen und dabei ein Repaint in einem Bereich ausloesen,
	// indem er niemals wirklich war.
    KSHORT nAscent = 0;

    const bool bTxtFrmVertical = GetInfo().GetTxtFrm()->IsVertical();

    const bool bUseFlyAscent = pFly && pFly->GetValidPosFlag() &&
                               0 != ( bTxtFrmVertical ?
                                      pFly->GetRefPoint().X() :
                                      pFly->GetRefPoint().Y() );

    if ( bUseFlyAscent )
         nAscent = static_cast<sal_uInt16>( Abs( int( bTxtFrmVertical ?
                                                  pFly->GetRelPos().X() :
                                                  pFly->GetRelPos().Y() ) ) );

    // check if be prefer to use the ascent of the last portion:
    if ( IsQuick() ||
         !bUseFlyAscent ||
         nAscent < rInf.GetLast()->GetAscent() )
    {
		nAscent = rInf.GetLast()->GetAscent();
    }
    else if( nAscent > nFlyAsc )
		nFlyAsc = nAscent;

	Point aBase( GetLeftMargin() + rInf.X(), Y() + nAscent );
    objectpositioning::AsCharFlags nMode = IsQuick() ? AS_CHAR_QUICK : 0;
	if( GetMulti() && GetMulti()->HasRotation() )
	{
        nMode |= AS_CHAR_ROTATE;
		if( GetMulti()->IsRevers() )
            nMode |= AS_CHAR_REVERSE;
	}

    Point aTmpBase( aBase );
    if ( GetInfo().GetTxtFrm()->IsVertical() )
        GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( aTmpBase );

	if( pFly )
	{
        pRet = new SwFlyCntPortion( *GetInfo().GetTxtFrm(), pFly, aTmpBase,
                                    nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, nMode );
		// Wir muessen sicherstellen, dass unser Font wieder im OutputDevice
		// steht. Es koennte sein, dass der FlyInCnt frisch eingefuegt wurde,
		// dann hat GetFlyFrm dazu gefuehrt, dass er neu angelegt wird.
		// Dessen Frames werden sofort formatiert, die verstellen den Font
		// und schon haben wir den Salat (3322).
		rInf.SelectFont();
		if( pRet->GetAscent() > nAscent )
		{
			aBase.Y() = Y() + pRet->GetAscent();
            nMode |= AS_CHAR_ULSPACE;
			if( !rInf.IsTest() )
                aTmpBase = aBase;
                if ( GetInfo().GetTxtFrm()->IsVertical() )
                    GetInfo().GetTxtFrm()->SwitchHorizontalToVertical( aTmpBase );

                pRet->SetBase( *rInf.GetTxtFrm(), aTmpBase, nTmpAscent,
                               nTmpDescent, nFlyAsc, nFlyDesc, nMode );
		}
	}
	else
	{
        pRet = new SwFlyCntPortion( *rInf.GetTxtFrm(), (SwDrawContact*)pFrmFmt->FindContactObj(),
           aTmpBase, nTmpAscent, nTmpDescent, nFlyAsc, nFlyDesc, nMode );
	}
	return pRet;
}



/*************************************************************************
 *						SwTxtFly::SwTxtFly()
 *************************************************************************/

SwTxtFly::SwTxtFly( const SwTxtFly& rTxtFly )
{
	pPage = rTxtFly.pPage;
    // --> OD 2006-08-15 #i68520#
    mpCurrAnchoredObj = rTxtFly.mpCurrAnchoredObj;
    // <--
	pCurrFrm = rTxtFly.pCurrFrm;
	pMaster = rTxtFly.pMaster;
    // --> OD 2006-08-15 #i68520#
    if( rTxtFly.mpAnchoredObjList )
	{
        mpAnchoredObjList = new SwAnchoredObjList( *(rTxtFly.mpAnchoredObjList) );
	}
	else
    {
        mpAnchoredObjList = NULL;
    }
    // <--

	bOn = rTxtFly.bOn;
	bLeftSide = rTxtFly.bLeftSide;
	bTopRule = rTxtFly.bTopRule;
}

void SwTxtFly::CtorInitTxtFly( const SwTxtFrm *pFrm )
{
    mbIgnoreCurrentFrame = sal_False;
    mbIgnoreContour = sal_False;
    // --> OD 2004-12-17 #118809#
    mbIgnoreObjsInHeaderFooter = sal_False;
    // <--
    pPage = pFrm->FindPageFrm();
	const SwFlyFrm* pTmp = pFrm->FindFlyFrm();
    // --> OD 2006-08-15 #i68520#
    mpCurrAnchoredObj = pTmp;
    // <--
	pCurrFrm = pFrm;
	pMaster = pCurrFrm->IsFollow() ? NULL : pCurrFrm;
    // --> OD 2006-08-15 #i68520#
    mpAnchoredObjList = NULL;
    // <--
    // Wenn wir nicht von einem Frame ueberlappt werden, oder wenn
	// es gar keine FlyCollection gibt, dann schaltet wir uns fuer immer ab.
	// Aber es koennte sein, dass waehrend der Formatierung eine Zeile
	// hinzukommt, die in einen Frame hineinragt. Deswegen keine Optimierung
	// per bOn = pSortedFlys && IsAnyFrm();
	bOn = pPage->GetSortedObjs() != 0;
	bTopRule = sal_True;
	bLeftSide = sal_False;
	nMinBottom = 0;
	nIndex = ULONG_MAX;
}

/*************************************************************************
 *						SwTxtFly::_GetFrm()
 *
 * IN:	dokumentglobal	(rRect)
 * OUT: framelokal		(return-Wert)
 * Diese Methode wird waehrend der Formatierung vom LineIter gerufen.
 * 1. um die naechste FlyPortion vorzubereiten
 * 2. um nach Aenderung der Zeilenhoehe neue Ueberlappungen festzustellen
 *************************************************************************/

SwRect SwTxtFly::_GetFrm( const SwRect &rRect, sal_Bool bTop ) const
{
	SwRect aRet;
	if( ForEach( rRect, &aRet, sal_True ) )
	{
        SWRECTFN( pCurrFrm )
		if( bTop )
            (aRet.*fnRect->fnSetTop)( (rRect.*fnRect->fnGetTop)() );

		// 8110: Bottom nicht immer anpassen.
        const SwTwips nRetBottom = (aRet.*fnRect->fnGetBottom)();
        const SwTwips nRectBottom = (rRect.*fnRect->fnGetBottom)();
        if ( (*fnRect->fnYDiff)( nRetBottom, nRectBottom ) > 0 ||
             (aRet.*fnRect->fnGetHeight)() < 0 )
            (aRet.*fnRect->fnSetBottom)( nRectBottom );
	}
	return aRet;
}

/*************************************************************************
 *						SwTxtFly::IsAnyFrm()
 *
 * IN: dokumentglobal
 * fuer die Printarea des aktuellen Frame
 *
 * dient zum Abschalten des SwTxtFly, wenn keine Objekte ueberlappen (Relax)
 *
 *************************************************************************/

sal_Bool SwTxtFly::IsAnyFrm() const
{
    SWAP_IF_SWAPPED( pCurrFrm )

	ASSERT( bOn, "IsAnyFrm: Why?" );
	SwRect aRect( pCurrFrm->Frm().Pos() + pCurrFrm->Prt().Pos(),
		pCurrFrm->Prt().SSize() );

    const sal_Bool bRet = ForEach( aRect, NULL, sal_False );
    UNDO_SWAP( pCurrFrm )
    return bRet;
}

/*************************************************************************
 *						SwTxtFly::IsAnyObj()
 *
 * IN: dokumentglobal
 * OUT: sal_True Wenn ein Rahmen oder DrawObj beruecksichtigt werden muss
 * Nur wenn IsAnyObj sal_False liefert, koennen Optimierungen benutzt werden
 * wie Paint/FormatEmpty fuer leere Absaetze
 * und auch das virtuelle Outputdevice.
 *************************************************************************/

sal_Bool SwTxtFly::IsAnyObj( const SwRect &rRect ) const
{
	ASSERT ( bOn, "SwTxtFly::IsAnyObj: Who's knocking?" );

	SwRect aRect( rRect );
	if ( aRect.IsEmpty() )
		aRect = SwRect( pCurrFrm->Frm().Pos() + pCurrFrm->Prt().Pos(),
						pCurrFrm->Prt().SSize() );

    const SwSortedObjs *pSorted = pPage->GetSortedObjs();
	if( pSorted ) // Eigentlich ist durch bOn sichergestellt, dass es an der
	// Seite Objekte gibt, aber wer weiss, wer inzwischen etwas geloescht hat.
	{
		for ( MSHORT i = 0; i < pSorted->Count(); ++i )
		{
            const SwAnchoredObject* pObj = (*pSorted)[i];

            const SwRect aBound( pObj->GetObjRectWithSpaces() );

			// Optimierung
            if( pObj->GetObjRect().Left() > aRect.Right() )
				continue;

            // --> OD 2006-08-15 #i68520#
            if( mpCurrAnchoredObj != pObj && aBound.IsOver( aRect ) )
            // <--
				return sal_True;
		}
	}
	return sal_False;
}

const SwCntntFrm* SwTxtFly::_GetMaster()
{
	pMaster = pCurrFrm;
	while( pMaster->IsFollow() )
		pMaster = (SwCntntFrm*)pMaster->FindMaster();
	return pMaster;
}

/*************************************************************************
 *						SwTxtFly::DrawTextOpaque()
 *
 * IN: dokumentglobal
 * DrawTextOpaque() wird von DrawText() gerufen.
 * Die Clipregions werden so gesetzt, dass nur die Teile ausgegeben werden,
 * die nicht in den Bereichen von FlyFrms liegen, die undurchsichtig und
 * ueber dem aktuellen Frame liegen.
 * Die On-Optimierung uebernimmt DrawText()!
 *************************************************************************/

sal_Bool SwTxtFly::DrawTextOpaque( SwDrawTextInfo &rInf )
{
	SwSaveClip aClipSave( rInf.GetpOut() );
	SwRect aRect( rInf.GetPos(), rInf.GetSize() );
	if( rInf.GetSpace() )
	{
		xub_StrLen nTmpLen = STRING_LEN == rInf.GetLen() ? rInf.GetText().Len() :
													  rInf.GetLen();
		if( rInf.GetSpace() > 0 )
		{
			xub_StrLen nSpaceCnt = 0;
			const xub_StrLen nEndPos = rInf.GetIdx() + nTmpLen;
			for( xub_StrLen nPos = rInf.GetIdx(); nPos < nEndPos; ++nPos )
			{
				if( CH_BLANK == rInf.GetText().GetChar( nPos ) )
					++nSpaceCnt;
			}
			if( nSpaceCnt )
				aRect.Width( aRect.Width() + nSpaceCnt * rInf.GetSpace() );
		}
		else
			aRect.Width( aRect.Width() - nTmpLen * rInf.GetSpace() );
	}

	if( aClipSave.IsOn() && rInf.GetOut().IsClipRegion() )
	{
		SwRect aClipRect( rInf.GetOut().GetClipRegion().GetBoundRect() );
		aRect.Intersection( aClipRect );
	}

	SwRegionRects aRegion( aRect );

	sal_Bool bOpaque = sal_False;
    // --> OD 2006-08-15 #i68520#
    const sal_uInt32 nCurrOrd = mpCurrAnchoredObj
                            ? mpCurrAnchoredObj->GetDrawObj()->GetOrdNum()
                            : SAL_MAX_UINT32;
    // <--
	ASSERT( !bTopRule, "DrawTextOpaque: Wrong TopRule" );

    // --> OD 2006-08-15 #i68520#
    SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
    if ( bOn && nCount > 0 )
    // <--
	{
        MSHORT nHellId = pPage->getRootFrm()->GetCurrShell()->getIDocumentDrawModelAccess()->GetHellId();
		for( MSHORT i = 0; i < nCount; ++i )
		{
            // --> OD 2006-08-15 #i68520#
            const SwAnchoredObject* pTmpAnchoredObj = (*mpAnchoredObjList)[i];
            if( dynamic_cast<const SwFlyFrm*>(pTmpAnchoredObj) &&
                mpCurrAnchoredObj != pTmpAnchoredObj )
            // <--
			{
                // --> OD 2006-08-15 #i68520#
                const SwFlyFrm* pFly = dynamic_cast<const SwFlyFrm*>(pTmpAnchoredObj);
                // <--
				if( aRegion.GetOrigin().IsOver( pFly->Frm() ) )
				{
					const SwFrmFmt *pFmt = pFly->GetFmt();
					const SwFmtSurround &rSur = pFmt->GetSurround();
					const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
						//Nur undurchsichtige und weiter oben liegende.
                    /// OD 08.10.2002 #103898# - add condition
                    /// <!(pFly->IsBackgroundTransparent() || pFly->IsShadowTransparent())>
                    if( !( pFly->IsBackgroundTransparent()
                           || pFly->IsShadowTransparent() ) &&
                        SURROUND_THROUGHT == rSur.GetSurround() &&
                        ( !rSur.IsAnchorOnly() ||
                          // --> OD 2006-08-15 #i68520#
                          GetMaster() == pFly->GetAnchorFrm() ||
                          // <--
                          ((FLY_AT_PARA != rAnchor.GetAnchorId()) &&
                           (FLY_AT_CHAR != rAnchor.GetAnchorId())
                          )
                        ) &&
                        // --> OD 2006-08-15 #i68520#
                        pTmpAnchoredObj->GetDrawObj()->GetLayer() != nHellId &&
                        nCurrOrd < pTmpAnchoredObj->GetDrawObj()->GetOrdNum()
                        // <--
                      )
					{
						//Ausser der Inhalt ist Transparent
						const SwNoTxtFrm *pNoTxt =
								pFly->Lower() && pFly->Lower()->IsNoTxtFrm()
												   ? (SwNoTxtFrm*)pFly->Lower()
												   : 0;
						if ( !pNoTxt ||
							 (!pNoTxt->IsTransparent() && !rSur.IsContour()) )
						{
							bOpaque = sal_True;
							aRegion -= pFly->Frm();
						}
					}
				}
			}
		}
	}

	Point aPos( rInf.GetPos().X(), rInf.GetPos().Y() + rInf.GetAscent() );
	const Point &rOld = rInf.GetPos();
	rInf.SetPos( aPos );

	if( !bOpaque )
	{
		if( rInf.GetKern() )
			rInf.GetFont()->_DrawStretchText( rInf );
		else
			rInf.GetFont()->_DrawText( rInf );
		rInf.SetPos( rOld );
		return sal_False;
	}
	else if( aRegion.Count() )
	{
		// Was fuer ein Aufwand ...
		SwSaveClip aClipVout( rInf.GetpOut() );
		for( MSHORT i = 0; i < aRegion.Count(); ++i )
		{
			SwRect &rRect = aRegion[i];
			if( rRect != aRegion.GetOrigin() )
				aClipVout.ChgClip( rRect );
			if( rInf.GetKern() )
				rInf.GetFont()->_DrawStretchText( rInf );
			else
				rInf.GetFont()->_DrawText( rInf );
		}
	}
	rInf.SetPos( rOld );
	return sal_True;
}

/*************************************************************************
 *						SwTxtFly::DrawFlyRect()
 *
 * IN: windowlokal
 * Zwei Feinheiten gilt es zu beachten:
 * 1) DrawRect() oberhalb des ClipRects sind erlaubt !
 * 2) FlyToRect() liefert groessere Werte als die Framedaten !
 *************************************************************************/

void SwTxtFly::DrawFlyRect( OutputDevice* pOut, const SwRect &rRect,
		const SwTxtPaintInfo &rInf, sal_Bool bNoGraphic )
{
	SwRegionRects aRegion( rRect );
	ASSERT( !bTopRule, "DrawFlyRect: Wrong TopRule" );
    // --> OD 2006-08-15 #i68520#
    SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
    if ( bOn && nCount > 0 )
    // <--
	{
        MSHORT nHellId = pPage->getRootFrm()->GetCurrShell()->getIDocumentDrawModelAccess()->GetHellId();
		for( MSHORT i = 0; i < nCount; ++i )
		{
            // --> OD 2006-08-15 #i68520#
            const SwAnchoredObject* pAnchoredObjTmp = (*mpAnchoredObjList)[i];
            if( mpCurrAnchoredObj != pAnchoredObjTmp &&
                dynamic_cast<const SwFlyFrm*>(pAnchoredObjTmp) )
            // <--
			{
                // --> OD 2006-08-15 #i68520#
                const SwFmtSurround& rSur = pAnchoredObjTmp->GetFrmFmt().GetSurround();
                // <--

                // OD 24.01.2003 #106593# - correct clipping of fly frame area.
                // Consider that fly frame background/shadow can be transparent
                // and <SwAlignRect(..)> fly frame area
                // --> OD 2006-08-15 #i68520#
                const SwFlyFrm* pFly = dynamic_cast<const SwFlyFrm*>(pAnchoredObjTmp);
                // <--
                // --> OD 2005-06-08 #i47804# - consider transparent graphics
                // and OLE objects.
                bool bClipFlyArea =
                        ( ( SURROUND_THROUGHT == rSur.GetSurround() )
                          // --> OD 2006-08-15 #i68520#
                          ? (pAnchoredObjTmp->GetDrawObj()->GetLayer() != nHellId)
                          // <--
                          : !rSur.IsContour() ) &&
                        !pFly->IsBackgroundTransparent() &&
                        !pFly->IsShadowTransparent() &&
                        ( !pFly->Lower() ||
                          !pFly->Lower()->IsNoTxtFrm() ||
                          !static_cast<const SwNoTxtFrm*>(pFly->Lower())->IsTransparent() );
                // <--
                if ( bClipFlyArea )
				{
                    // --> OD 2006-08-15 #i68520#
                    SwRect aFly( pAnchoredObjTmp->GetObjRect() );
                    // <--
                    // OD 24.01.2003 #106593#
                    ::SwAlignRect( aFly, pPage->getRootFrm()->GetCurrShell() );
					if( aFly.Width() > 0 && aFly.Height() > 0 )
						aRegion -= aFly;
				}
			}
		}
	}

    for( MSHORT i = 0; i < aRegion.Count(); ++i )
    {
        if ( bNoGraphic )
        {
            pOut->DrawRect( aRegion[i].SVRect() );
        }
        else
        {
            if(((SvxBrushItem*)-1) != rInf.GetBrushItem())
            {
                ::DrawGraphic(rInf.GetBrushItem(), pOut, rInf.GetBrushRect(), aRegion[i] );
            }
            else
            {
                OSL_ENSURE(false, "DrawRect: Uninitialized BrushItem!" );
            }
        }
    }
}

// --> OD 2004-10-06 #i26945# - change first parameter:
// Now it's the <SwAnchoredObject> instance of the floating screen object
sal_Bool SwTxtFly::GetTop( const SwAnchoredObject* _pAnchoredObj,
                           const sal_Bool bInFtn,
                           const sal_Bool bInFooterOrHeader )
// <--
{
    // --> OD 2006-08-15 #i68520#
    // <mpCurrAnchoredObj> is set, if <pCurrFrm> is inside a fly frame
    if( _pAnchoredObj != mpCurrAnchoredObj )
    // <--
	{
        // --> OD 2004-10-06 #i26945#
        const SdrObject* pNew = _pAnchoredObj->GetDrawObj();
        // <--
		// #102344# Ignore connectors which have one or more connections
		if(pNew && pNew->ISA(SdrEdgeObj))
		{
			if(((SdrEdgeObj*)pNew)->GetConnectedNode(sal_True)
				|| ((SdrEdgeObj*)pNew)->GetConnectedNode(sal_False))
			{
				return sal_False;
			}
		}

        if( ( bInFtn || bInFooterOrHeader ) && bTopRule )
        {
            // --> OD 2004-10-06 #i26945#
            const SwFrmFmt& rFrmFmt = _pAnchoredObj->GetFrmFmt();
            const SwFmtAnchor& rNewA = rFrmFmt.GetAnchor();
            // <--
            if (FLY_AT_PAGE == rNewA.GetAnchorId())
            {
                if ( bInFtn )
                    return sal_False;

                if ( bInFooterOrHeader )
                {
                    SwFmtVertOrient aVert( rFrmFmt.GetVertOrient() );
                    sal_Bool bVertPrt = aVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ||
                            aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA;
                    if( bVertPrt )
                        return sal_False;
                }
            }
        }

        // --> OD 2006-08-15 #i68520#
        // bEvade: consider pNew, if we are not inside a fly
        //         consider pNew, if pNew is lower of <mpCurrAnchoredObj>
        sal_Bool bEvade = !mpCurrAnchoredObj ||
                          Is_Lower_Of( dynamic_cast<const SwFlyFrm*>(mpCurrAnchoredObj), pNew);

        if ( !bEvade )
		{
            // We are currently inside a fly frame and pNew is not
            // inside this fly frame. We can do some more checks if
            // we have to consider pNew.

            // If bTopRule is not set, we ignore the frame types.
            // We directly check the z-order
			if ( !bTopRule )
				bEvade = sal_True;
			else
			{
				// innerhalb von verketteten Flys wird nur Lowern ausgewichen
                // --> OD 2006-08-15 #i68520#
                const SwFmtChain &rChain = mpCurrAnchoredObj->GetFrmFmt().GetChain();
                // <--
				if ( !rChain.GetPrev() && !rChain.GetNext() )
				{
                    // --> OD 2004-10-06 #i26945#
                    const SwFmtAnchor& rNewA = _pAnchoredObj->GetFrmFmt().GetAnchor();
                    // <--
                    // --> OD 2006-08-15 #i68520#
                    const SwFmtAnchor& rCurrA = mpCurrAnchoredObj->GetFrmFmt().GetAnchor();
                    // <--

                    // If <mpCurrAnchoredObj> is anchored as character, its content
                    // does not wrap around pNew
                    if (FLY_AS_CHAR == rCurrA.GetAnchorId())
						return sal_False;

                    // If pNew is anchored to page and <mpCurrAnchoredObj is not anchored
                    // to page, the content of <mpCurrAnchoredObj> does not wrap around pNew
                    // If both pNew and <mpCurrAnchoredObj> are anchored to page, we can do
                    // some more checks
                    if (FLY_AT_PAGE == rNewA.GetAnchorId())
                    {
                        if (FLY_AT_PAGE == rCurrA.GetAnchorId())
                        {
                            bEvade = sal_True;
                        }
						else
							return sal_False;
					}
                    else if (FLY_AT_PAGE == rCurrA.GetAnchorId())
						return sal_False; // Seitengebundene weichen nur seitengeb. aus
					else if (FLY_AT_FLY == rNewA.GetAnchorId())
						bEvade = sal_True; // Nicht seitengeb. weichen Rahmengeb. aus
					else if( FLY_AT_FLY == rCurrA.GetAnchorId() )
						return sal_False; // Rahmengebundene weichen abs.geb. nicht aus
                    // --> OD 2006-01-30 #i57062#
                    // In order to avoid loop situation, it's decided to adjust
                    // the wrapping behaviour of content of at-paragraph/at-character
                    // anchored objects to one in the page header/footer and
                    // the document body --> content of at-paragraph/at-character
                    // anchored objects doesn't wrap around each other.
//                    else if( bInFooterOrHeader )
//                        return sal_False;  // In header or footer no wrapping
//                                           // if both bounded at paragraph
//                    else // Zwei Flies mit (auto-)absatzgebunder Verankerung ...
//                    // ... entscheiden nach der Reihenfolge ihrer Anker im Dok.
//                      bEvade = rNewA.GetCntntAnchor()->nNode.GetIndex() <=
//                              rCurrA.GetCntntAnchor()->nNode.GetIndex();
                    else
                        return sal_False;
                    // <--
				}
			}

            // aber: es wird niemals einem hierarchisch untergeordnetem
			// ausgewichen und ausserdem braucht nur bei Ueberlappung
			// ausgewichen werden.
            // --> OD 2006-08-15 #i68520#
            bEvade &= ( mpCurrAnchoredObj->GetDrawObj()->GetOrdNum() < pNew->GetOrdNum() );
            // <--
			if( bEvade )
			{
                // --> OD 2006-08-15 #i68520#
                SwRect aTmp( _pAnchoredObj->GetObjRectWithSpaces() );
                if ( !aTmp.IsOver( mpCurrAnchoredObj->GetObjRectWithSpaces() ) )
                    bEvade = sal_False;
                // <--
			}
		}

        if ( bEvade )
		{
            // --> OD 2004-10-06 #i26945#
            const SwFmtAnchor& rNewA = _pAnchoredObj->GetFrmFmt().GetAnchor();
            // <--
            ASSERT( FLY_AS_CHAR != rNewA.GetAnchorId(),
                    "Don't call GetTop with a FlyInCntFrm" );
            if (FLY_AT_PAGE == rNewA.GetAnchorId())
				return sal_True;  // Seitengebundenen wird immer ausgewichen.

			// Wenn absatzgebundene Flys in einem FlyCnt gefangen sind, so
			// endet deren Einflussbereich an den Grenzen des FlyCnt!
			// Wenn wir aber gerade den Text des FlyCnt formatieren, dann
			// muss er natuerlich dem absatzgebundenen Frm ausweichen!
			// pCurrFrm ist der Anker von pNew?
            // --> OD 2004-10-06 #i26945#
            const SwFrm* pTmp = _pAnchoredObj->GetAnchorFrm();
            // <--
			if( pTmp == pCurrFrm )
				return sal_True;
			if( pTmp->IsTxtFrm() && ( pTmp->IsInFly() || pTmp->IsInFtn() ) )
			{
                // --> OD 2004-10-06 #i26945#
                Point aPos = _pAnchoredObj->GetObjRect().Pos();
                // <--
				pTmp = GetVirtualUpper( pTmp, aPos );
			}
            // --> OD 2004-10-06 #i26945#
            // --> OD 2004-11-29 #115759#
            // If <pTmp> is a text frame inside a table, take the upper
            // of the anchor frame, which contains the anchor position.
            else if ( pTmp->IsTxtFrm() && pTmp->IsInTab() )
            {
                pTmp = const_cast<SwAnchoredObject*>(_pAnchoredObj)
                                ->GetAnchorFrmContainingAnchPos()->GetUpper();
            }
            // <--
            // --> OD 2004-05-13 #i28701# - consider all objects in same context,
            // if wrapping style is considered on object positioning.
            // Thus, text will wrap around negative positioned objects.
            // --> OD 2004-08-25 #i3317# - remove condition on checking,
            // if wrappings style is considered on object postioning.
            // Thus, text is wrapping around negative positioned objects.
            // --> OD 2004-10-20 #i35640# - no consideration of negative
            // positioned objects, if wrapping style isn't considered on
            // object position and former text wrapping is applied.
            // This condition is typically for documents imported from the
            // OpenOffice.org file format.
            const IDocumentSettingAccess* pIDSA = pCurrFrm->GetTxtNode()->getIDocumentSettingAccess();
            if ( (  pIDSA->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) ||
                   !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) ) &&
                 ::FindKontext( pTmp, 0 ) == ::FindKontext( pCurrFrm, 0 ) )
            {
                return sal_True;
            }
            // <--

            const SwFrm* pHeader = 0;
            if ( pCurrFrm->GetNext() != pTmp &&
                 ( IsFrmInSameKontext( pTmp, pCurrFrm ) ||
                   // --> #i13832#, #i24135# wrap around objects in page header
                   ( !pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) &&
                     0 != ( pHeader = pTmp->FindFooterOrHeader() ) &&
                     !pHeader->IsFooterFrm() &&
                     pCurrFrm->IsInDocBody() ) ) )
                   // <--
			{
				if( pHeader || FLY_AT_FLY == rNewA.GetAnchorId() )
					return sal_True;

                // Compare indices:
				// Den Index des anderen erhalten wir immer ueber das Ankerattr.
				sal_uLong nTmpIndex = rNewA.GetCntntAnchor()->nNode.GetIndex();
				// Jetzt wird noch ueberprueft, ob der aktuelle Absatz vor dem
				// Anker des verdraengenden Objekts im Text steht, dann wird
				// nicht ausgewichen.
				// Der Index wird moeglichst ueber einen SwFmtAnchor ermittelt,
				// da sonst recht teuer.
				if( ULONG_MAX == nIndex )
					nIndex = pCurrFrm->GetNode()->GetIndex();

				if( nIndex >= nTmpIndex )
					return sal_True;
			}
		}
	}
    return sal_False;
}
// --> OD 2006-08-15 #i68520#
struct AnchoredObjOrder
{
    sal_Bool mbR2L;
    SwRectFn mfnRect;

    AnchoredObjOrder( const sal_Bool bR2L,
                       SwRectFn fnRect )
        : mbR2L( bR2L ),
          mfnRect( fnRect )
    {}

    bool operator()( const SwAnchoredObject* pListedAnchoredObj,
                     const SwAnchoredObject* pNewAnchoredObj )
    {
        const SwRect aBoundRectOfListedObj( pListedAnchoredObj->GetObjRectWithSpaces() );
        const SwRect aBoundRectOfNewObj( pNewAnchoredObj->GetObjRectWithSpaces() );
        if ( ( mbR2L &&
               ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ==
                 (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
             ( !mbR2L &&
               ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ==
                 (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
        {
            SwTwips nTopDiff =
                (*mfnRect->fnYDiff)( (aBoundRectOfNewObj.*mfnRect->fnGetTop)(),
                                    (aBoundRectOfListedObj.*mfnRect->fnGetTop)() );
            if ( nTopDiff == 0 &&
                 ( ( mbR2L &&
                     ( (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() >
                       (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() ) ) ||
                   ( !mbR2L &&
                     ( (aBoundRectOfNewObj.*mfnRect->fnGetRight)() <
                       (aBoundRectOfListedObj.*mfnRect->fnGetRight)() ) ) ) )
            {
                return true;
            }
            else if ( nTopDiff > 0 )
            {
                return true;
            }
        }
        else if ( ( mbR2L &&
                    ( (aBoundRectOfListedObj.*mfnRect->fnGetRight)() >
                      (aBoundRectOfNewObj.*mfnRect->fnGetRight)() ) ) ||
                  ( !mbR2L &&
                    ( (aBoundRectOfListedObj.*mfnRect->fnGetLeft)() <
                      (aBoundRectOfNewObj.*mfnRect->fnGetLeft)() ) ) )
        {
            return true;
        }

        return false;
    }
};

// --> OD 2006-08-15 #i68520#
SwAnchoredObjList* SwTxtFly::InitAnchoredObjList()
{
	ASSERT( pCurrFrm, "InitFlyList: No Frame, no FlyList" );
    // --> OD 2006-08-15 #i68520#
    ASSERT( !mpAnchoredObjList, "InitFlyList: FlyList already initialized" );
    // <--

    SWAP_IF_SWAPPED( pCurrFrm )

    const SwSortedObjs *pSorted = pPage->GetSortedObjs();
    const sal_uInt32 nCount = pSorted ? pSorted->Count() : 0;
    // --> #108724# Page header/footer content doesn't have to wrap around
    //              floating screen objects
    const bool bFooterHeader = 0 != pCurrFrm->FindFooterOrHeader();
    const IDocumentSettingAccess* pIDSA = pCurrFrm->GetTxtNode()->getIDocumentSettingAccess();
    // --> OD 2005-01-12 #i40155# - check, if frame is marked not to wrap
    const sal_Bool bWrapAllowed = ( pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) ||
                                    ( !pCurrFrm->IsInFtn() && !bFooterHeader ) ) &&
                                      !SwLayouter::FrmNotToWrap( *pCurrFrm->GetTxtNode()->getIDocumentLayoutAccess(), *pCurrFrm );
    // <--

    bOn = sal_False;

	if( nCount && bWrapAllowed )
	{
        // --> OD 2006-08-15 #i68520#
        mpAnchoredObjList = new SwAnchoredObjList();
        // <--

        // --> OD 2004-06-18 #i28701# - consider complete frame area for new
        // text wrapping
        SwRect aRect;
        if ( pIDSA->get(IDocumentSettingAccess::USE_FORMER_TEXT_WRAPPING) )
        {
            aRect = pCurrFrm->Prt();
            aRect += pCurrFrm->Frm().Pos();
        }
        else
        {
            aRect = pCurrFrm->Frm();
        }
		// Wir machen uns etwas kleiner als wir sind,
		// damit Ein-Twip-Ueberlappungen ignoriert werden. (#49532)
        SWRECTFN( pCurrFrm )
        const long nRight = (aRect.*fnRect->fnGetRight)() - 1;
        const long nLeft = (aRect.*fnRect->fnGetLeft)() + 1;
        const sal_Bool bR2L = pCurrFrm->IsRightToLeft();

        const IDocumentDrawModelAccess* pIDDMA = pCurrFrm->GetTxtNode()->getIDocumentDrawModelAccess();

        for( sal_uInt32 i = 0; i < nCount; i++ )
		{
            // --> OD 2006-08-15 #i68520#
//            SwAnchoredObject* pAnchoredObj = (*pSorted)[ i ];
//            const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );

//            // OD 2004-01-15 #110582# - do not consider hidden objects
//            // OD 2004-05-13 #i28701# - check, if object has to be considered
//            // for text wrap.
//            if ( !pDoc->IsVisibleLayerId( pAnchoredObj->GetDrawObj()->GetLayer() ) ||
//                 !pAnchoredObj->ConsiderForTextWrap() ||
//                 nRight < (aBound.*fnRect->fnGetLeft)() ||
//                 (*fnRect->fnYDiff)( (aRect.*fnRect->fnGetTop)(),
//                                     (aBound.*fnRect->fnGetBottom)() ) > 0 ||
//                 nLeft > (aBound.*fnRect->fnGetRight)() ||
//                 // --> OD 2004-12-17 #118809# - If requested, do not consider
//                 // objects in page header|footer for text frames not in page
//                 // header|footer. This is requested for the calculation of
//                 // the base offset for objects <SwTxtFrm::CalcBaseOfstForFly()>
//                 ( mbIgnoreObjsInHeaderFooter && !bFooterHeader &&
//                   pAnchoredObj->GetAnchorFrm()->FindFooterOrHeader() ) ||
//                 // <--
//                 // --> FME 2004-07-14 #i20505# Do not consider oversized objects
//                 (aBound.*fnRect->fnGetHeight)() >
//                 2 * (pPage->Frm().*fnRect->fnGetHeight)() )
//                 // <--
//            {
//              continue;
//            }
            SwAnchoredObject* pAnchoredObj = (*pSorted)[ i ];
            if ( !pIDDMA->IsVisibleLayerId( pAnchoredObj->GetDrawObj()->GetLayer() ) ||
                 !pAnchoredObj->ConsiderForTextWrap() ||
                 ( mbIgnoreObjsInHeaderFooter && !bFooterHeader &&
                   pAnchoredObj->GetAnchorFrm()->FindFooterOrHeader() ) )
            {
                continue;
            }

            const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
            if ( nRight < (aBound.*fnRect->fnGetLeft)() ||
                 (*fnRect->fnYDiff)( (aRect.*fnRect->fnGetTop)(),
                                     (aBound.*fnRect->fnGetBottom)() ) > 0 ||
                 nLeft > (aBound.*fnRect->fnGetRight)() ||
                 (aBound.*fnRect->fnGetHeight)() >
                                    2 * (pPage->Frm().*fnRect->fnGetHeight)() )
            {
                continue;
            }
            // <--

            // --> OD 2004-10-06 #i26945# - pass <pAnchoredObj> to method
            // <GetTop(..)> instead of only the <SdrObject> instance of the
            // anchored object
            if ( GetTop( pAnchoredObj, pCurrFrm->IsInFtn(), bFooterHeader ) )
            // <--
			{
                // OD 11.03.2003 #107862# - adjust insert position:
                // overlapping objects should be sorted from left to right and
                // inside left to right sorting from top to bottom.
                // If objects on the same position are found, they are sorted
                // on its width.
                // --> OD 2006-08-15 #i68520#
//                sal_uInt16 nPos = pFlyList->Count();
//                while ( nPos )
//                {
//                    SdrObject* pTmpObj = (*pFlyList)[ --nPos ];
//                    const SwRect aBoundRectOfTmpObj( GetBoundRect( pTmpObj ) );
//                    if ( ( bR2L &&
//                           ( (aBoundRectOfTmpObj.*fnRect->fnGetRight)() ==
//                             (aBound.*fnRect->fnGetRight)() ) ) ||
//                         ( !bR2L &&
//                           ( (aBoundRectOfTmpObj.*fnRect->fnGetLeft)() ==
//                             (aBound.*fnRect->fnGetLeft)() ) ) )
//                    {
//                        SwTwips nTopDiff =
//                            (*fnRect->fnYDiff)( (aBound.*fnRect->fnGetTop)(),
//                                                (aBoundRectOfTmpObj.*fnRect->fnGetTop)() );
//                        if ( nTopDiff == 0 &&
//                             ( ( bR2L &&
//                                 ( (aBound.*fnRect->fnGetLeft)() >
//                                   (aBoundRectOfTmpObj.*fnRect->fnGetLeft)() ) ) ||
//                               ( !bR2L &&
//                                 ( (aBound.*fnRect->fnGetRight)() <
//                                   (aBoundRectOfTmpObj.*fnRect->fnGetRight)() ) ) ) )
//                        {
//                            ++nPos;
//                            break;
//                        }
//                        else if ( nTopDiff > 0 )
//                        {
//                            ++nPos;
//                            break;
//                        }
//                    }
//                    else if ( ( bR2L &&
//                                ( (aBoundRectOfTmpObj.*fnRect->fnGetRight)() >
//                                  (aBound.*fnRect->fnGetRight)() ) ) ||
//                              ( !bR2L &&
//                                ( (aBoundRectOfTmpObj.*fnRect->fnGetLeft)() <
//                                  (aBound.*fnRect->fnGetLeft)() ) ) )
//                    {
//                        ++nPos;
//                        break;
//                    }
//                }
//                SdrObject* pSdrObj = pAnchoredObj->DrawObj();
//                pFlyList->C40_INSERT( SdrObject, pSdrObj, nPos );
                {
                    SwAnchoredObjList::iterator aInsPosIter =
                            std::lower_bound( mpAnchoredObjList->begin(),
                                              mpAnchoredObjList->end(),
                                              pAnchoredObj,
                                              AnchoredObjOrder( bR2L, fnRect ) );

                    mpAnchoredObjList->insert( aInsPosIter, pAnchoredObj );
                }
                // <--

                const SwFmtSurround &rFlyFmt = pAnchoredObj->GetFrmFmt().GetSurround();
                // --> OD 2006-08-15 #i68520#
                if ( rFlyFmt.IsAnchorOnly() &&
                     pAnchoredObj->GetAnchorFrm() == GetMaster() )
                // <--
				{
                    const SwFmtVertOrient &rTmpFmt =
                                    pAnchoredObj->GetFrmFmt().GetVertOrient();
                    if( text::VertOrientation::BOTTOM != rTmpFmt.GetVertOrient() )
                        nMinBottom = ( bVert && nMinBottom ) ?
                                     Min( nMinBottom, aBound.Left() ) :
                                     Max( nMinBottom, (aBound.*fnRect->fnGetBottom)() );
				}

				bOn = sal_True;
			}
		}
		if( nMinBottom )
		{
            SwTwips nMax = (pCurrFrm->GetUpper()->*fnRect->fnGetPrtBottom)();
            if( (*fnRect->fnYDiff)( nMinBottom, nMax ) > 0 )
				nMinBottom = nMax;
		}
	}
	else
    {
        // --> OD 2006-08-15 #i68520#
        mpAnchoredObjList = new SwAnchoredObjList();
        // <--
    }

    UNDO_SWAP( pCurrFrm )

    // --> OD 2006-08-15 #i68520#
    return mpAnchoredObjList;
    // <--
}
// <--

SwTwips SwTxtFly::CalcMinBottom() const
{
	SwTwips nRet = 0;
    const SwSortedObjs *pDrawObj = GetMaster()->GetDrawObjs();
    const sal_uInt32 nCount = pDrawObj ? pDrawObj->Count() : 0;
	if( nCount )
	{
		SwTwips nEndOfFrm = pCurrFrm->Frm().Bottom();
        for( sal_uInt32 i = 0; i < nCount; i++ )
		{
            SwAnchoredObject* pAnchoredObj = (*pDrawObj)[ i ];
            const SwFmtSurround &rFlyFmt = pAnchoredObj->GetFrmFmt().GetSurround();
			if( rFlyFmt.IsAnchorOnly() )
			{
                const SwFmtVertOrient &rTmpFmt =
                                    pAnchoredObj->GetFrmFmt().GetVertOrient();
                if( text::VertOrientation::BOTTOM != rTmpFmt.GetVertOrient() )
				{
                    const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
					if( aBound.Top() < nEndOfFrm )
						nRet = Max( nRet, aBound.Bottom() );
				}
			}
		}
		SwTwips nMax = pCurrFrm->GetUpper()->Frm().Top() +
					   pCurrFrm->GetUpper()->Prt().Bottom();
		if( nRet > nMax )
			nRet = nMax;
	}
	return nRet;
}

/*************************************************************************
 * Hier erfolgt die Berechnung der Kontur ...
 * CalcBoundRect(..) und andere
 *************************************************************************/

/*************************************************************************
 * class SwContourCache
 *************************************************************************/

SwContourCache::SwContourCache() :
    nPntCnt( 0 ), nObjCnt( 0 )
{
	memset( (SdrObject**)pSdrObj, 0, sizeof(pSdrObj) );
	memset( pTextRanger, 0, sizeof(pTextRanger) );
}

SwContourCache::~SwContourCache()
{
	for( MSHORT i = 0; i < nObjCnt; delete pTextRanger[ i++ ] )
		;
}

void SwContourCache::ClrObject( MSHORT nPos )
{
	ASSERT( pTextRanger[ nPos ], "ClrObject: Already cleared. Good Bye!" );
	nPntCnt -= pTextRanger[ nPos ]->GetPointCount();
	delete pTextRanger[ nPos ];
	--nObjCnt;
	memmove( (SdrObject**)pSdrObj + nPos, pSdrObj + nPos + 1,
			 ( nObjCnt - nPos ) * sizeof( SdrObject* ) );
	memmove( pTextRanger + nPos, pTextRanger + nPos + 1,
			 ( nObjCnt - nPos ) * sizeof( TextRanger* ) );
}

void ClrContourCache( const SdrObject *pObj )
{
	if( pContourCache && pObj )
		for( MSHORT i = 0; i < pContourCache->GetCount(); ++i )
			if( pObj == pContourCache->GetObject( i ) )
			{
				pContourCache->ClrObject( i );
				break;
			}
}

void ClrContourCache()
{
	if( pContourCache )
	{
		for( MSHORT i = 0; i < pContourCache->GetCount();
			 delete pContourCache->pTextRanger[ i++ ] )
			 ;
		pContourCache->nObjCnt = 0;
		pContourCache->nPntCnt = 0;
	}
}

/*************************************************************************
 * SwContourCache::CalcBoundRect
 * berechnet das Rechteck, welches vom Objekt in der angegebenen Zeile
 * ueberdeckt wird.
 * Bei _nicht_ konturumflossenen Objekten ist dies einfach die Ueber-
 * lappung von BoundRect (inkl. Abstand!) und Zeile,
 * bei Konturumfluss wird das Polypolygon des Objekts abgeklappert
 *************************************************************************/
// --> OD 2006-08-15 #i68520#
const SwRect SwContourCache::CalcBoundRect( const SwAnchoredObject* pAnchoredObj,
                                            const SwRect &rLine,
                                            const SwTxtFrm* pFrm,
                                            const long nXPos,
                                            const sal_Bool bRight )
{
    SwRect aRet;
    const SwFrmFmt* pFmt = &(pAnchoredObj->GetFrmFmt());
	if( pFmt->GetSurround().IsContour() &&
        ( !pAnchoredObj->ISA(SwFlyFrm) ||
          ( static_cast<const SwFlyFrm*>(pAnchoredObj)->Lower() &&
            static_cast<const SwFlyFrm*>(pAnchoredObj)->Lower()->IsNoTxtFrm() ) ) )
	{
        aRet = pAnchoredObj->GetObjRectWithSpaces();
		if( aRet.IsOver( rLine ) )
		{
			if( !pContourCache )
				pContourCache = new SwContourCache;

            aRet = pContourCache->ContourRect(
                    pFmt, pAnchoredObj->GetDrawObj(), pFrm, rLine, nXPos, bRight );
		}
		else
			aRet.Width( 0 );
	}
	else
	{
        aRet = pAnchoredObj->GetObjRectWithSpaces();
	}

	return aRet;
}
// <--

const SwRect SwContourCache::ContourRect( const SwFmt* pFmt,
    const SdrObject* pObj, const SwTxtFrm* pFrm, const SwRect &rLine,
    const long nXPos, const sal_Bool bRight )
{
	SwRect aRet;
	MSHORT nPos = 0; // Suche im Cache ...
	while( nPos < GetCount() && pObj != pSdrObj[ nPos ] )
		++nPos;
	if( GetCount() == nPos ) // nicht gefunden
	{
		if( nObjCnt == POLY_CNT )
		{
			nPntCnt -= pTextRanger[ --nObjCnt ]->GetPointCount();
			delete pTextRanger[ nObjCnt ];
		}
		::basegfx::B2DPolyPolygon aPolyPolygon;
		::basegfx::B2DPolyPolygon* pPolyPolygon = 0L;

		if ( pObj->ISA(SwVirtFlyDrawObj) )
		{
			// Vorsicht #37347: Das GetContour() fuehrt zum Laden der Grafik,
			// diese aendert dadurch ggf. ihre Groesse, ruft deshalb ein
			// ClrObject() auf.
			PolyPolygon aPoly;
			if( !((SwVirtFlyDrawObj*)pObj)->GetFlyFrm()->GetContour( aPoly ) )
				aPoly = PolyPolygon( ((SwVirtFlyDrawObj*)pObj)->
									 GetFlyFrm()->Frm().SVRect() );
			aPolyPolygon.clear();
			aPolyPolygon.append(aPoly.getB2DPolyPolygon());
		}
		else
		{
            if( !pObj->ISA( E3dObject ) )
			{
				aPolyPolygon = pObj->TakeXorPoly();
			}

			::basegfx::B2DPolyPolygon aContourPoly(pObj->TakeContour());
			pPolyPolygon = new ::basegfx::B2DPolyPolygon(aContourPoly);
		}
		const SvxLRSpaceItem &rLRSpace = pFmt->GetLRSpace();
		const SvxULSpaceItem &rULSpace = pFmt->GetULSpace();
		memmove( pTextRanger + 1, pTextRanger, nObjCnt * sizeof( TextRanger* ) );
		memmove( (SdrObject**)pSdrObj + 1, pSdrObj, nObjCnt++ * sizeof( SdrObject* ) );
		pSdrObj[ 0 ] = pObj; // Wg. #37347 darf das Object erst nach dem
							 // GetContour() eingetragen werden.
        pTextRanger[ 0 ] = new TextRanger( aPolyPolygon, pPolyPolygon, 20,
            (sal_uInt16)rLRSpace.GetLeft(), (sal_uInt16)rLRSpace.GetRight(),
            pFmt->GetSurround().IsOutside(), sal_False, pFrm->IsVertical() );
        pTextRanger[ 0 ]->SetUpper( rULSpace.GetUpper() );
		pTextRanger[ 0 ]->SetLower( rULSpace.GetLower() );

		delete pPolyPolygon;
		// UPPER_LOWER_TEST
#ifdef DBG_UTIL
        const ViewShell* pTmpViewShell = pFmt->GetDoc()->GetCurrentViewShell();
        if( pTmpViewShell )
		{
            sal_Bool bT2 = pTmpViewShell->GetViewOptions()->IsTest2();
            sal_Bool bT6 = pTmpViewShell->GetViewOptions()->IsTest6();
			if( bT2 || bT6 )
			{
				if( bT2 )
					pTextRanger[ 0 ]->SetFlag7( sal_True );
				else
					pTextRanger[ 0 ]->SetFlag6( sal_True );
			}
		}
#endif
		nPntCnt += pTextRanger[ 0 ]->GetPointCount();
		while( nPntCnt > POLY_MAX && nObjCnt > POLY_MIN )
		{
			nPntCnt -= pTextRanger[ --nObjCnt ]->GetPointCount();
			delete pTextRanger[ nObjCnt ];
		}
	}
	else if( nPos )
	{
		const SdrObject* pTmpObj = pSdrObj[ nPos ];
		TextRanger* pTmpRanger = pTextRanger[ nPos ];
		memmove( (SdrObject**)pSdrObj + 1, pSdrObj, nPos * sizeof( SdrObject* ) );
		memmove( pTextRanger + 1, pTextRanger, nPos * sizeof( TextRanger* ) );
		pSdrObj[ 0 ] = pTmpObj;
		pTextRanger[ 0 ] = pTmpRanger;
	}
    SWRECTFN( pFrm )
    long nTmpTop = (rLine.*fnRect->fnGetTop)();
    // fnGetBottom is top + height
    long nTmpBottom = (rLine.*fnRect->fnGetBottom)();

    Range aRange( Min( nTmpTop, nTmpBottom ), Max( nTmpTop, nTmpBottom ) );

	SvLongs *pTmp = pTextRanger[ 0 ]->GetTextRanges( aRange );

	MSHORT nCount;
	if( 0 != ( nCount = pTmp->Count() ) )
	{
		MSHORT nIdx = 0;
        while( nIdx < nCount && (*pTmp)[ nIdx ] < nXPos )
			++nIdx;
		sal_Bool bOdd = nIdx % 2 ? sal_True : sal_False;
		sal_Bool bSet = sal_True;
		if( bOdd )
			--nIdx; // innerhalb eines Intervalls
        else if( ! bRight && ( nIdx >= nCount || (*pTmp)[ nIdx ] != nXPos ) )
		{
			if( nIdx )
				nIdx -= 2; // ein Intervall nach links gehen
			else
				bSet = sal_False; // vor dem erstem Intervall
		}

		if( bSet && nIdx < nCount )
		{
            (aRet.*fnRect->fnSetTopAndHeight)( (rLine.*fnRect->fnGetTop)(),
                                               (rLine.*fnRect->fnGetHeight)() );
            (aRet.*fnRect->fnSetLeft)( (*pTmp)[ nIdx ] );
            (aRet.*fnRect->fnSetRight)( (*pTmp)[ nIdx + 1 ] + 1 );
		}
	}
	return aRet;
}

/*************************************************************************
 *						SwContourCache::ShowContour()
 * zeichnet die PolyPolygone des Caches zu Debugzwecken.
 *************************************************************************/
#ifdef DBG_UTIL

void SwContourCache::ShowContour( OutputDevice* pOut, const SdrObject* pObj,
	const Color& rClosedColor, const Color& rOpenColor )
{
	MSHORT nPos = 0; // Suche im Cache ...
	while( nPos < POLY_CNT && pObj != pSdrObj[ nPos ] )
		++nPos;
	if( POLY_CNT != nPos )
	{
		const PolyPolygon* pPol = pTextRanger[ nPos ]->GetLinePolygon();
		if( !pPol )
			pPol = &(pTextRanger[ nPos ]->GetPolyPolygon());
		for( MSHORT i = 0; i < pPol->Count(); ++i )
		{
			pOut->SetLineColor( rOpenColor );
			const Polygon& rPol = (*pPol)[ i ];
			MSHORT nCount = rPol.GetSize();
			if( nCount > 1 && rPol[ 0 ] == rPol[ nCount - 1 ] )
				pOut->SetLineColor( rClosedColor );
			pOut->DrawPolygon( rPol );
		}
#if OSL_DEBUG_LEVEL > 1
		static KSHORT nRadius = 0;
		if( nRadius )
		{
			KSHORT nHalf = nRadius / 2;
			Size aSz( nRadius, nRadius );
			for( MSHORT i = 0; i < pPol->Count(); ++i )
			{
				const Polygon& rPol = (*pPol)[ i ];
				MSHORT nCount = rPol.GetSize();
				for( MSHORT k = 0; k < nCount; ++k )
				{
					Point aPt( rPol[ k ] );
					aPt.X() -= nHalf;
					aPt.Y() -= nHalf;
					Rectangle aTmp( aPt, aSz );
					pOut->DrawEllipse( aTmp );
				}
			}
		}
#endif
	}
}
#endif

/*************************************************************************
 *						SwTxtFly::ShowContour()
 * zeichnet die PolyPolygone des Caches zu Debugzwecken.
 *************************************************************************/
#ifdef DBG_UTIL

void SwTxtFly::ShowContour( OutputDevice* pOut )
{
	MSHORT nFlyCount;
    if( bOn && ( 0 != ( nFlyCount = static_cast<sal_uInt16>(GetAnchoredObjList()->size() ) ) ) )
	{
		Color aRedColor( COL_LIGHTRED );
		Color aGreenColor( COL_LIGHTGREEN );
		Color aSaveColor( pOut->GetLineColor() );
		for( MSHORT j = 0; j < nFlyCount; ++j )
		{
            const SwAnchoredObject* pObj = (*mpAnchoredObjList)[ j ];
            if( !pObj->GetFrmFmt().GetSurround().IsContour() )
			{
                Rectangle aRect = pObj->GetObjRectWithSpaces().SVRect();
				pOut->DrawRect( aRect );
				continue;
			}
            pContourCache->ShowContour( pOut, pObj->GetDrawObj(), aRedColor, aGreenColor );
		}
		pOut->SetLineColor( aSaveColor );
	}
}
#endif

/*************************************************************************
 *						SwTxtFly::ForEach()
 *
 * sucht nach dem ersten Objekt, welches mit dem Rechteck ueberlappt
 *
 *************************************************************************/

sal_Bool SwTxtFly::ForEach( const SwRect &rRect, SwRect* pRect, sal_Bool bAvoid ) const
{
    SWAP_IF_SWAPPED( pCurrFrm )

	sal_Bool bRet = sal_False;
    // --> OD 2006-08-15 #i68520#
    SwAnchoredObjList::size_type nCount( bOn ? GetAnchoredObjList()->size() : 0 );
    if ( bOn && nCount > 0 )
    // <--
	{
        for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
		{
            // --> OD 2006-08-15 #i68520#
            const SwAnchoredObject* pAnchoredObj = (*mpAnchoredObjList)[i];

            SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() );
            // <--

            // Optimierung
            SWRECTFN( pCurrFrm )
            if( (aRect.*fnRect->fnGetLeft)() > (rRect.*fnRect->fnGetRight)() )
				break;
            // --> OD 2006-08-15 #i68520#
            if ( mpCurrAnchoredObj != pAnchoredObj && aRect.IsOver( rRect ) )
            // <--
			{
                // --> OD 2006-08-15 #i68520#
                const SwFmt* pFmt( &(pAnchoredObj->GetFrmFmt()) );
                const SwFmtSurround &rSur = pFmt->GetSurround();
                // <--
				if( bAvoid )
				{
					// Wenn der Text drunter durchlaeuft, bleibt die
					// Formatierung unbeeinflusst. Im LineIter::DrawText()
					// muessen "nur" geschickt die ClippingRegions gesetzt werden ...
					const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
					if( ( SURROUND_THROUGHT == rSur.GetSurround() &&
						  ( !rSur.IsAnchorOnly() ||
                            // --> OD 2006-08-15 #i68520#
                            GetMaster() == pAnchoredObj->GetAnchorFrm() ||
                            // <--
                            ((FLY_AT_PARA != rAnchor.GetAnchorId()) &&
                             (FLY_AT_CHAR != rAnchor.GetAnchorId())) ) )
						|| aRect.Top() == WEIT_WECH )
						continue;
				}

                // --> OD 2006-01-20 #i58642#
                // Compare <GetMaster()> instead of <pCurrFrm> with the anchor
                // frame of the anchored object, because a follow frame have
                // to ignore the anchored objects of its master frame.
                // Note: Anchored objects are always registered at the master
                //       frame, exception are as-character anchored objects,
                //       but these aren't handled here.
                // --> OD 2006-08-15 #i68520#
                if ( mbIgnoreCurrentFrame &&
                     GetMaster() == pAnchoredObj->GetAnchorFrm() )
                    continue;
                // <--

				if( pRect )
				{
                    // --> OD 2006-08-15 #i68520#
                    SwRect aFly = AnchoredObjToRect( pAnchoredObj, rRect );
                    // <--
					if( aFly.IsEmpty() || !aFly.IsOver( rRect ) )
						continue;
                    if( !bRet || (
                        ( !pCurrFrm->IsRightToLeft() &&
                          ( (aFly.*fnRect->fnGetLeft)() <
                            (pRect->*fnRect->fnGetLeft)() ) ) ||
                        ( pCurrFrm->IsRightToLeft() &&
                          ( (aFly.*fnRect->fnGetRight)() >
                            (pRect->*fnRect->fnGetRight)() ) ) ) )
						*pRect = aFly;
					if( rSur.IsContour() )
					{
						bRet = sal_True;
						continue;
					}
				}
				bRet = sal_True;
				break;
			}
		}
	}

    UNDO_SWAP( pCurrFrm )

	return bRet;
}

/*************************************************************************
 *						SwTxtFly::GetPos()
 *
 * liefert die Position im sorted Array zurueck
 *************************************************************************/

// --> OD 2006-08-15 #i68520#
SwAnchoredObjList::size_type SwTxtFly::GetPos( const SwAnchoredObject* pAnchoredObj ) const
{
    SwAnchoredObjList::size_type nCount = GetAnchoredObjList()->size();
    SwAnchoredObjList::size_type nRet = 0;
    while ( nRet < nCount && pAnchoredObj != (*mpAnchoredObjList)[ nRet ] )
        ++nRet;
    return nRet;
}
// <--

/*************************************************************************
 *						SwTxtFly::CalcRightMargin()
 *
 * pObj ist das Object, der uns gerade ueberlappt.
 * pCurrFrm ist der aktuelle Textframe, der ueberlappt wird.
 * Der rechte Rand ist der rechte Rand oder
 * er wird durch das naechste Object, welches in die Zeile ragt, bestimmt.
 *************************************************************************/
// --> OD 2006-08-15 #i68520#
void SwTxtFly::CalcRightMargin( SwRect &rFly,
                                SwAnchoredObjList::size_type nFlyPos,
                                const SwRect &rLine ) const
{
	// Normalerweise ist der rechte Rand der rechte Rand der Printarea.
    ASSERT( ! pCurrFrm->IsVertical() || ! pCurrFrm->IsSwapped(),
            "SwTxtFly::CalcRightMargin with swapped frame" )
    SWRECTFN( pCurrFrm )
    // --> OD 2004-12-14 #118796# - correct determination of right of printing area
    SwTwips nRight = (pCurrFrm->*fnRect->fnGetPrtRight)();
    // <--
    SwTwips nFlyRight = (rFly.*fnRect->fnGetRight)();
	SwRect aLine( rLine );
    (aLine.*fnRect->fnSetRight)( nRight );
    (aLine.*fnRect->fnSetLeft)( (rFly.*fnRect->fnGetLeft)() );

	// Es koennte aber sein, dass in die gleiche Zeile noch ein anderes
	// Object hineinragt, welches _ueber_ uns liegt.
	// Wunder der Technik: Flys mit Durchlauf sind fuer die darunterliegenden
	// unsichtbar, das heisst, dass sie bei der Berechnung der Raender
	// anderer Flys ebenfalls nicht auffallen.
	// 3301: pNext->Frm().IsOver( rLine ) ist noetig
    // --> OD 2006-08-15 #i68520#
    SwSurround eSurroundForTextWrap;
    // <--

	sal_Bool bStop = sal_False;
    // --> OD 2006-08-15 #i68520#
    SwAnchoredObjList::size_type nPos = 0;
    // <--

    // --> OD 2006-08-15 #i68520#
    while( nPos < mpAnchoredObjList->size() && !bStop )
    // <--
	{
		if( nPos == nFlyPos )
		{
			++nPos;
			continue;
		}
        // --> OD 2006-08-15 #i68520#
        const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nPos++ ];
        if ( pNext == mpCurrAnchoredObj )
			continue;
        eSurroundForTextWrap = _GetSurroundForTextWrap( pNext );
        if( SURROUND_THROUGHT == eSurroundForTextWrap )
			continue;
        // <--

        const SwRect aTmp( SwContourCache::CalcBoundRect
                ( pNext, aLine, pCurrFrm, nFlyRight, sal_True ) );
        SwTwips nTmpRight = (aTmp.*fnRect->fnGetRight)();

		// Optimierung:
		// In nNextTop wird notiert, an welcher Y-Positon mit Aenderung der
		// Rahmenverhaeltnisse gerechnet werden muss. Dies dient dazu, dass,
		// obwohl nur die Rahmen in der aktuellen Zeilenhoehe betrachtet werden,
		// bei Rahmen ohne Umlauf die Zeilenhoehe so erhoeht wird, dass mit einer
		// einzigen Zeile die Unterkante das Rahmens oder ggf. die Oberkante des
		// naechsten Rahmen erreicht wird.
		// Insbesondere bei HTML-Dokumenten kommen oft (Dummy-)Absaetze in einer
		// 2-Pt.-Schrift vor, bis diese einem groesseren Rahmen ausgewichen sind,
		// erforderte es frueher Unmengen von Leerzeilen.
        const long nTmpTop = (aTmp.*fnRect->fnGetTop)();
        if( (*fnRect->fnYDiff)( nTmpTop, (aLine.*fnRect->fnGetTop)() ) > 0 )
		{
            if( (*fnRect->fnYDiff)( nNextTop, nTmpTop ) > 0 )
                SetNextTop( nTmpTop ); // Die Oberkante des "naechsten" Rahmens
		}
        else if( ! (aTmp.*fnRect->fnGetWidth)() ) // Typisch fuer Objekte mit Konturumlauf
		{   // Bei Objekten mit Konturumlauf, die vor der aktuellen Zeile beginnen
			// und hinter ihr enden, trotzdem aber nicht mit ihr ueberlappen,
			// muss die Optimierung ausgeschaltet werden, denn bereits in der
			// naechsten Zeile kann sich dies aendern.
            if( ! (aTmp.*fnRect->fnGetHeight)() ||
                (*fnRect->fnYDiff)( (aTmp.*fnRect->fnGetBottom)(),
                                    (aLine.*fnRect->fnGetTop)() ) > 0 )
				SetNextTop( 0 );
		}
		if( aTmp.IsOver( aLine ) && nTmpRight > nFlyRight )
		{
			nFlyRight = nTmpRight;
            if( SURROUND_RIGHT == eSurroundForTextWrap ||
                SURROUND_PARALLEL == eSurroundForTextWrap )
			{
                // der FlyFrm wird ueberstimmt.
                if( nRight > nFlyRight )
                    nRight = nFlyRight;
                bStop = sal_True;
            }
		}
	}
    (rFly.*fnRect->fnSetRight)( nRight );
}
// <--

/*************************************************************************
 *						SwTxtFly::CalcLeftMargin()
 *
 * pFly ist der FlyFrm, der uns gerade ueberlappt.
 * pCurrFrm ist der aktuelle Textframe, der ueberlappt wird.
 * Der linke Rand ist der linke Rand der aktuellen PrintArea oder
 * er wird durch den vorigen FlyFrm, der in die Zeile ragt, bestimmt.
 *************************************************************************/
// --> OD 2006-08-15 #i68520#
void SwTxtFly::CalcLeftMargin( SwRect &rFly,
                               SwAnchoredObjList::size_type nFlyPos,
                               const SwRect &rLine ) const
{
    ASSERT( ! pCurrFrm->IsVertical() || ! pCurrFrm->IsSwapped(),
            "SwTxtFly::CalcLeftMargin with swapped frame" )
    SWRECTFN( pCurrFrm )
    // --> OD 2004-12-14 #118796# - correct determination of left of printing area
    SwTwips nLeft = (pCurrFrm->*fnRect->fnGetPrtLeft)();
    // <--
    const SwTwips nFlyLeft = (rFly.*fnRect->fnGetLeft)();

    if( nLeft > nFlyLeft )
		nLeft = rFly.Left();

    SwRect aLine( rLine );
    (aLine.*fnRect->fnSetLeft)( nLeft );

	// Es koennte aber sein, dass in die gleiche Zeile noch ein anderes
	// Object hineinragt, welches _ueber_ uns liegt.
	// Wunder der Technik: Flys mit Durchlauf sind fuer die darunterliegenden
	// unsichtbar, das heisst, dass sie bei der Berechnung der Raender
	// anderer Flys ebenfalls nicht auffallen.
	// 3301: pNext->Frm().IsOver( rLine ) ist noetig

    // --> OD 2006-08-15 #i68520#
    SwAnchoredObjList::size_type nMyPos = nFlyPos;
    while( ++nFlyPos < mpAnchoredObjList->size() )
    // <--
	{
        // --> OD 2006-08-15 #i68520#
        const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
        const SwRect aTmp( pNext->GetObjRectWithSpaces() );
        // <--
        if( (aTmp.*fnRect->fnGetLeft)() >= nFlyLeft )
			break;
	}

	while( nFlyPos )
	{
		if( --nFlyPos == nMyPos )
			continue;
        // --> OD 2006-08-15 #i68520#
        const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
        if( pNext == mpCurrAnchoredObj )
            continue;
        SwSurround eSurroundForTextWrap = _GetSurroundForTextWrap( pNext );
        if( SURROUND_THROUGHT == eSurroundForTextWrap )
            continue;
        // <--

		const SwRect aTmp( SwContourCache::CalcBoundRect
                ( pNext, aLine, pCurrFrm, nFlyLeft, sal_False ) );

        if( (aTmp.*fnRect->fnGetLeft)() < nFlyLeft && aTmp.IsOver( aLine ) )
		{
            // --> OD 2004-12-14 #118796# - no '+1', because <..fnGetRight>
            // returns the correct value.
            SwTwips nTmpRight = (aTmp.*fnRect->fnGetRight)();
            if ( nLeft <= nTmpRight )
                nLeft = nTmpRight;
            // <--

			break;
		}
	}
    (rFly.*fnRect->fnSetLeft)( nLeft );
}
// <--

/*************************************************************************
 *						SwTxtFly::FlyToRect()
 *
 * IN:	dokumentglobal	(rRect)
 * OUT: dokumentglobal	(return-Wert)
 * Liefert zu einem SwFlyFrm das von ihm in Anspruch genommene Rechteck
 * unter Beruecksichtigung der eingestellten Attribute fuer den Abstand
 * zum Text zurueck.
 *************************************************************************/
// --> OD 2006-08-15 #i68520#
SwRect SwTxtFly::AnchoredObjToRect( const SwAnchoredObject* pAnchoredObj,
                            const SwRect &rLine ) const
{
    SWRECTFN( pCurrFrm )

    const long nXPos = pCurrFrm->IsRightToLeft() ?
                       rLine.Right() :
                       (rLine.*fnRect->fnGetLeft)();

    SwRect aFly = mbIgnoreContour ?
                  pAnchoredObj->GetObjRectWithSpaces() :
                  SwContourCache::CalcBoundRect( pAnchoredObj, rLine, pCurrFrm,
                                                 nXPos, ! pCurrFrm->IsRightToLeft() );

    if( !aFly.Width() )
		return aFly;

    SetNextTop( (aFly.*fnRect->fnGetBottom)() ); // Damit die Zeile ggf. bis zur Unterkante
								 // des Rahmens waechst.
    SwAnchoredObjList::size_type nFlyPos = GetPos( pAnchoredObj );

	// Bei LEFT und RIGHT vergroessern wir das Rechteck.
	// Hier gibt es einige Probleme, wenn mehrere Frames zu sehen sind.
	// Zur Zeit wird nur der einfachste Fall angenommen:
	// LEFT bedeutet, dass der Text links vom Frame fliessen soll,
	// d.h. der Frame blaeht sich bis zum rechten Rand der Printarea
	// oder bis zum naechsten Frame auf.
	// Bei RIGHT ist es umgekehrt.
	// Ansonsten wird immer der eingestellte Abstand zwischen Text
	// und Frame aufaddiert.
    switch( _GetSurroundForTextWrap( pAnchoredObj ) )
	{
		case SURROUND_LEFT :
		{
			CalcRightMargin( aFly, nFlyPos, rLine );
			break;
		}
		case SURROUND_RIGHT :
		{
			CalcLeftMargin( aFly, nFlyPos, rLine );
			break;
		}
		case SURROUND_NONE :
		{
			CalcRightMargin( aFly, nFlyPos, rLine );
			CalcLeftMargin( aFly, nFlyPos, rLine );
			break;
		}
        default:
            break;
	}
	return aFly;
}

// --> OD 2006-08-15 #i68520#
// new method <_GetSurroundForTextWrap(..)> replaces methods
// <CalcSmart(..)> and <GetOrder(..)>
/*************************************************************************
 *						SwTxtFly::CalcSmart()
 *
 * CalcSmart() liefert die Umlaufform zurueck.
 *
 * Auf beiden Seiten ist weniger als 2 cm Platz fuer den Text
 * 	 => kein Umlauf ( SURROUND_NONE )
 * Auf genau einer Seite ist mehr als 2 cm Platz
 *   => Umlauf auf dieser Seite ( SURROUND_LEFT / SURROUND_RIGHT )
 * Auf beiden Seiten ist mehr als 2 cm Platz, das Objekt ist breiter als 1,5 cm
 * 	 => Umlauf auf der breiteren Seite ( SURROUND_LEFT / SURROUND_RIGHT )
 * Auf beiden Seiten ist mehr als 2 cm Platz, das Objekt ist schmaler als 1,5 cm
 * 	 => beidseitiger Umlauf ( SURROUND_PARALLEL	)
 *
 *************************************************************************/

// Umfluss nur auf Seiten mit mindestens 2 cm Platz fuer den Text
#define TEXT_MIN 1134
// Beidseitiger Umfluss bis zu einer Rahmenbreite von maximal 1,5 cm
#define FRAME_MAX 850

SwSurround SwTxtFly::_GetSurroundForTextWrap( const SwAnchoredObject* pAnchoredObj ) const
{
    const SwFrmFmt* pFmt = &(pAnchoredObj->GetFrmFmt());
    const SwFmtSurround &rFlyFmt = pFmt->GetSurround();
    SwSurround eSurroundForTextWrap = rFlyFmt.GetSurround();

    if( rFlyFmt.IsAnchorOnly() && pAnchoredObj->GetAnchorFrm() != GetMaster() )
    {
        const SwFmtAnchor& rAnchor = pFmt->GetAnchor();
        if ((FLY_AT_PARA == rAnchor.GetAnchorId()) ||
            (FLY_AT_CHAR == rAnchor.GetAnchorId()))
        {
            return SURROUND_NONE;
        }
    }

    // Beim Durchlauf und Nowrap wird smart ignoriert.
    if( SURROUND_THROUGHT == eSurroundForTextWrap ||
        SURROUND_NONE == eSurroundForTextWrap )
        return eSurroundForTextWrap;

    // left is left and right is right
    if ( pCurrFrm->IsRightToLeft() )
    {
        if ( SURROUND_LEFT == eSurroundForTextWrap )
            eSurroundForTextWrap = SURROUND_RIGHT;
        else if ( SURROUND_RIGHT == eSurroundForTextWrap )
            eSurroundForTextWrap = SURROUND_LEFT;
    }

    // "idealer Seitenumlauf":
    if ( SURROUND_IDEAL == eSurroundForTextWrap )
    {
        SWRECTFN( pCurrFrm )
        const long nCurrLeft = (pCurrFrm->*fnRect->fnGetPrtLeft)();
        const long nCurrRight = (pCurrFrm->*fnRect->fnGetPrtRight)();
        const SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() );
        long nFlyLeft = (aRect.*fnRect->fnGetLeft)();
        long nFlyRight = (aRect.*fnRect->fnGetRight)();

        if ( nFlyRight < nCurrLeft || nFlyLeft > nCurrRight )
            eSurroundForTextWrap = SURROUND_PARALLEL;
        else
        {
            long nLeft = nFlyLeft - nCurrLeft;
            long nRight = nCurrRight - nFlyRight;
            if( nFlyRight - nFlyLeft > FRAME_MAX )
            {
                if( nLeft < nRight )
                    nLeft = 0;
                else
                    nRight = 0;
            }
            if( nLeft < TEXT_MIN )
                nLeft = 0;
            if( nRight < TEXT_MIN )
                nRight = 0;
            if( nLeft )
                eSurroundForTextWrap = nRight ? SURROUND_PARALLEL : SURROUND_LEFT;
            else
                eSurroundForTextWrap = nRight ? SURROUND_RIGHT: SURROUND_NONE;
        }
    }

    return eSurroundForTextWrap;
}

/*************************************************************************
 *						SwTxtFly::IsAnyFrm( SwRect )
 *
 * IN: dokumentglobal
 *
 * dient zum Abschalten des SwTxtFly, wenn keine Objekte ueberlappen (Relax)
 *
 *************************************************************************/

sal_Bool SwTxtFly::IsAnyFrm( const SwRect &rLine ) const
{

    SWAP_IF_SWAPPED( pCurrFrm )

	ASSERT( bOn, "IsAnyFrm: Why?" );

    const sal_Bool bRet = ForEach( rLine, NULL, sal_False );
    UNDO_SWAP( pCurrFrm )
    return bRet;
}