Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/sw/source/core/text/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 57 kB image not shown  

Quelle  txtfly.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   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 .
 */


#include <vcl/outdev.hxx>

#include <pagefrm.hxx>
#include <rootfrm.hxx>
#include <pam.hxx>
#include <swfont.hxx>
#include <swregion.hxx>
#include <dflyobj.hxx>
#include <drawfont.hxx>
#include <flyfrm.hxx>
#include <flyfrms.hxx>
#include <fmtornt.hxx>
#include <frmatr.hxx>
#include <frmtool.hxx>
#include <ndtxt.hxx>
#include <txtfly.hxx>
#include "inftxt.hxx"
#include "porrst.hxx"
#include "txtpaint.hxx"
#include <notxtfrm.hxx>
#include <fmtcnct.hxx>
#include <svx/obj3d.hxx>
#include <editeng/txtrange.hxx>
#include <editeng/lrspitem.hxx>
#include <editeng/ulspitem.hxx>
#include <fmtsrnd.hxx>
#include <fmtanchr.hxx>
#include <frmfmt.hxx>
#include <fmtfollowtextflow.hxx>
#include <pagedesc.hxx>
#include <sortedobjs.hxx>
#include <IDocumentDrawModelAccess.hxx>
#include <IDocumentSettingAccess.hxx>
#include <formatlinebreak.hxx>
#include <svx/svdoedge.hxx>

#ifdef DBG_UTIL
#include <viewsh.hxx>
#include <doc.hxx>
#endif

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

namespace
{
    // #i68520#
    struct AnchoredObjOrder
    {
        bool mbR2L;
        SwRectFn mfnRect;

        AnchoredObjOrder( const 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;
        }
    };
}

SwContourCache::SwContourCache() :
    mnPointCount( 0 )
{
}

SwContourCache::~SwContourCache()
{
}

void SwContourCache::ClrObject( sal_uInt16 nPos )
{
    mnPointCount -= mvItems[ nPos ].mxTextRanger->GetPointCount();
    mvItems.erase(mvItems.begin() + nPos);
}

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

void ClrContourCache()
{
    if( pContourCache )
    {
        pContourCache->mvItems.clear();
        pContourCache->mnPointCount = 0;
    }
}

// #i68520#
SwRect SwContourCache::CalcBoundRect( const SwAnchoredObject* pAnchoredObj,
                                            const SwRect &rLine,
                                            const SwTextFrame* pFrame,
                                            const tools::Long nXPos,
                                            const bool bRight )
{
    SwRect aRet;
    const SwFrameFormat* pFormat = pAnchoredObj->GetFrameFormat();
    bool bHandleContour(pFormat->GetSurround().IsContour());

    if(!bHandleContour)
    {
        // RotateFlyFrame3: Object has no set contour, but for rotated
        // FlyFrames we can create a 'default' contour to make text
        // flow around the free, non-covered
        const SwFlyFreeFrame* pSwFlyFreeFrame(dynamic_castconst SwFlyFreeFrame* >(pAnchoredObj));

        if(nullptr != pSwFlyFreeFrame && pSwFlyFreeFrame->supportsAutoContour())
        {
            bHandleContour = true;
        }
    }

    const SwFlyFrame* pFlyFrame = pAnchoredObj->DynCastFlyFrame();
    const SwFrame* pLower = pFlyFrame
        ? static_cast<const SwFlyFrame*>(pAnchoredObj)->Lower() : nullptr;
    if( bHandleContour &&
        ( !pFlyFrame || ( pLower && pLower->IsNoTextFrame() ) ) )
    {
        aRet = pAnchoredObj->GetObjRectWithSpaces();
        if( aRet.Overlaps( rLine ) )
        {
            if( !pContourCache )
                pContourCache = new SwContourCache;

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

    return aRet;
}

SwRect SwContourCache::ContourRect( const SwFormat* pFormat,
    const SdrObject* pObj, const SwTextFrame* pFrame, const SwRect &rLine,
    const tools::Long nXPos, const bool bRight )
{
    SwRect aRet;
    sal_uInt16 nPos = 0; // Search in the Cache
    while( nPos < GetCount() && pObj != mvItems[ nPos ].mpSdrObj )
        ++nPos;
    if( GetCount() == nPos ) // Not found
    {
        if( GetCount() == POLY_CNT )
        {
            mnPointCount -= mvItems.back().mxTextRanger->GetPointCount();
            mvItems.pop_back();
        }
        ::basegfx::B2DPolyPolygon aPolyPolygon;
        std::optional<::basegfx::B2DPolyPolygon> pPolyPolygon;

        if ( auto pVirtFlyDrawObj = dynamic_castconst SwVirtFlyDrawObj *>( pObj ) )
        {
            // GetContour() causes the graphic to be loaded, which may cause
            // the graphic to change its size, call ClrObject()
            tools::PolyPolygon aPoly;
            if( !pVirtFlyDrawObj->GetFlyFrame()->GetContour( aPoly ) )
                aPoly = tools::PolyPolygon( pVirtFlyDrawObj->
                                     GetFlyFrame()->getFrameArea().SVRect() );
            aPolyPolygon.clear();
            aPolyPolygon.append(aPoly.getB2DPolyPolygon());
        }
        else
        {
            if( DynCastE3dObject( pObj ) == nullptr )
            {
                aPolyPolygon = pObj->TakeXorPoly();
            }

            pPolyPolygon = pObj->TakeContour();
        }
        const SvxLRSpaceItem &rLRSpace = pFormat->GetLRSpace();
        const SvxULSpaceItem &rULSpace = pFormat->GetULSpace();
        CacheItem item{ pObj, // due to #37347 the Object must be entered only after GetContour()
                        std::make_unique<TextRanger>(
                            aPolyPolygon, pPolyPolygon ? &*pPolyPolygon : nullptr, 20,
                            o3tl::narrowing<sal_uInt16>(rLRSpace.ResolveLeft({})),
                            o3tl::narrowing<sal_uInt16>(rLRSpace.ResolveRight({})),
                            pFormat->GetSurround().IsOutside(), false, pFrame->IsVertical()) };
        mvItems.insert(mvItems.begin(), std::move(item));
        mvItems[0].mxTextRanger->SetUpper( rULSpace.GetUpper() );
        mvItems[0].mxTextRanger->SetLower( rULSpace.GetLower() );

        pPolyPolygon.reset();

        mnPointCount += mvItems[0].mxTextRanger->GetPointCount();
        while( mnPointCount > POLY_MAX && mvItems.size() > POLY_MIN )
        {
            mnPointCount -= mvItems.back().mxTextRanger->GetPointCount();
            mvItems.pop_back();
        }
    }
    else if( nPos )
    {
        CacheItem item = std::move(mvItems[nPos]);
        mvItems.erase(mvItems.begin() + nPos);
        mvItems.insert(mvItems.begin(), std::move(item));
    }
    SwRectFnSet aRectFnSet(pFrame);
    tools::Long nTmpTop = aRectFnSet.GetTop(rLine);
    // fnGetBottom is top + height
    tools::Long nTmpBottom = aRectFnSet.GetBottom(rLine);

    Range aRange( std::min( nTmpTop, nTmpBottom ), std::max( nTmpTop, nTmpBottom ) );

    std::deque<tools::Long>* pTmp = mvItems[0].mxTextRanger->GetTextRanges( aRange );

    const size_t nCount = pTmp->size();
    if( 0 != nCount )
    {
        size_t nIdx = 0;
        while( nIdx < nCount && (*pTmp)[ nIdx ] < nXPos )
            ++nIdx;
        bool bOdd = nIdx % 2;
        bool bSet = true;
        if( bOdd )
            --nIdx; // within interval
        else if( ! bRight && ( nIdx >= nCount || (*pTmp)[ nIdx ] != nXPos ) )
        {
            if( nIdx )
                nIdx -= 2; // an interval to the left
            else
                bSet = false// before the first interval
        }

        if( bSet && nIdx < nCount )
        {
            aRectFnSet.SetTopAndHeight( aRet, aRectFnSet.GetTop(rLine),
                                               aRectFnSet.GetHeight(rLine) );
            aRectFnSet.SetLeft( aRet, (*pTmp)[ nIdx ] );
            aRectFnSet.SetRight( aRet, (*pTmp)[ nIdx + 1 ] + 1 );
        }
    }
    return aRet;
}

SwTextFly::SwTextFly()
    : m_pPage(nullptr)
    , mpCurrAnchoredObj(nullptr)
    , m_pCurrFrame(nullptr)
    , m_pMaster(nullptr)
    , m_nMinBottom(0)
    , m_nNextTop(0)
    , m_nCurrFrameNodeIndex(0)
    , m_bOn(false)
    , m_bTopRule(false)
    , mbIgnoreCurrentFrame(false)
    , mbIgnoreContour(false)
    , mbIgnoreObjsInHeaderFooter(false)

{
}

SwTextFly::SwTextFly( const SwTextFrame *pFrame )
{
    CtorInitTextFly( pFrame );
}

SwTextFly::SwTextFly( const SwTextFly& rTextFly )
{
    m_pPage = rTextFly.m_pPage;
    mpCurrAnchoredObj = rTextFly.mpCurrAnchoredObj;
    m_pCurrFrame = rTextFly.m_pCurrFrame;
    m_pMaster = rTextFly.m_pMaster;
    if( rTextFly.mpAnchoredObjList )
    {
        mpAnchoredObjList.reset( new SwAnchoredObjList( *(rTextFly.mpAnchoredObjList) ) );
    }

    m_bOn = rTextFly.m_bOn;
    m_bTopRule = rTextFly.m_bTopRule;
    m_nMinBottom = rTextFly.m_nMinBottom;
    m_nNextTop = rTextFly.m_nNextTop;
    m_nCurrFrameNodeIndex = rTextFly.m_nCurrFrameNodeIndex;
    mbIgnoreCurrentFrame = rTextFly.mbIgnoreCurrentFrame;
    mbIgnoreContour = rTextFly.mbIgnoreContour;
    mbIgnoreObjsInHeaderFooter = rTextFly.mbIgnoreObjsInHeaderFooter;
}

SwTextFly::~SwTextFly()
{
}

void SwTextFly::CtorInitTextFly( const SwTextFrame *pFrame )
{
    mbIgnoreCurrentFrame = false;
    mbIgnoreContour = false;
    mbIgnoreObjsInHeaderFooter = false;
    m_pPage = pFrame->FindPageFrame();
    const SwFlyFrame* pTmp = pFrame->FindFlyFrame();
    // #i68520#
    mpCurrAnchoredObj = pTmp;
    m_pCurrFrame = pFrame;
    m_pMaster = m_pCurrFrame->IsFollow() ? nullptr : m_pCurrFrame;
    // If we're not overlapped by a frame or if a FlyCollection does not exist
    // at all, we switch off forever.
    // It could be, however, that a line is added while formatting, that
    // extends into a frame.
    // That's why we do not optimize for: bOn = pSortedFlys && IsAnyFrame();
    m_bOn = m_pPage->GetSortedObjs() != nullptr;
    m_bTopRule = true;
    m_nMinBottom = 0;
    m_nNextTop = 0;
    m_nCurrFrameNodeIndex = NODE_OFFSET_MAX;
}

SwRect SwTextFly::GetFrame_( const SwRect &rRect ) const
{
    SwRect aRet;
    if( ForEach( rRect, &aRet, true ) )
    {
        SwRectFnSet aRectFnSet(m_pCurrFrame);
        aRectFnSet.SetTop( aRet, aRectFnSet.GetTop(rRect) );

        // Do not always adapt the bottom
        const SwTwips nRetBottom = aRectFnSet.GetBottom(aRet);
        const SwTwips nRectBottom = aRectFnSet.GetBottom(rRect);
        if ( aRectFnSet.YDiff( nRetBottom, nRectBottom ) > 0 ||
             aRectFnSet.GetHeight(aRet) < 0 )
            aRectFnSet.SetBottom( aRet, nRectBottom );
    }
    return aRet;
}

bool SwTextFly::IsAnyFrame() const
{
    SwSwapIfSwapped swap(const_cast<SwTextFrame *>(m_pCurrFrame));

    OSL_ENSURE( m_bOn, "IsAnyFrame: Why?" );
    SwRect aRect(m_pCurrFrame->getFrameArea().Pos() + m_pCurrFrame->getFramePrintArea().Pos(),
        m_pCurrFrame->getFramePrintArea().SSize());

    return ForEach( aRect, nullptr, false );
}

bool SwTextFly::IsAnyObj( const SwRect &rRect ) const
{
    OSL_ENSURE( m_bOn, "SwTextFly::IsAnyObj: Who's knocking?" );

    SwRect aRect( rRect );
    if ( aRect.IsEmpty() )
    {
        aRect = SwRect(m_pCurrFrame->getFrameArea().Pos() + m_pCurrFrame->getFramePrintArea().Pos(),
                        m_pCurrFrame->getFramePrintArea().SSize());

        SwTwips nLower = m_pCurrFrame->GetLowerMarginForFlyIntersect();
        if (nLower > 0)
        {
            aRect.AddBottom(nLower);
        }
    }

    const SwSortedObjs *pSorted = m_pPage->GetSortedObjs();
    if( pSorted ) // bOn actually makes sure that we have objects on the side,
                  // but who knows who deleted something in the meantime?
    {
        for ( size_t i = 0; i < pSorted->size(); ++i )
        {
            const SwAnchoredObject* pObj = (*pSorted)[i];

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

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

            // #i68520#
            if( mpCurrAnchoredObj != pObj && aBound.Overlaps( aRect ) )
                return true;
        }
    }
    return false;
}

const SwTextFrame* SwTextFly::GetMaster_()
{
    m_pMaster = m_pCurrFrame;
    while (m_pMaster && m_pMaster->IsFollow())
        m_pMaster = m_pMaster->FindMaster();
    return m_pMaster;
}

void SwTextFly::DrawTextOpaque( SwDrawTextInfo &rInf )
{
    SwSaveClip aClipSave( rInf.GetpOut() );
    SwRect aRect( rInf.GetPos(), rInf.GetSize() );
    if( rInf.GetSpace() )
    {
        TextFrameIndex const nTmpLen = TextFrameIndex(COMPLETE_STRING) == rInf.GetLen()
                ? TextFrameIndex(rInf.GetText().getLength())
                : rInf.GetLen();
        if( rInf.GetSpace() > 0 )
        {
            sal_Int32 nSpaceCnt = 0;
            const TextFrameIndex nEndPos = rInf.GetIdx() + nTmpLen;
            for (TextFrameIndex nPos = rInf.GetIdx(); nPos < nEndPos; ++nPos)
            {
                if (CH_BLANK == rInf.GetText()[sal_Int32(nPos)])
                    ++nSpaceCnt;
            }
            if( nSpaceCnt )
                aRect.Width( aRect.Width() + nSpaceCnt * rInf.GetSpace() );
        }
        else
            aRect.Width( aRect.Width() - sal_Int32(nTmpLen) * rInf.GetSpace() );
    }

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

    SwRegionRects aRegion( aRect );

    bool bOpaque = false;
    // #i68520#
    const sal_uInt32 nCurrOrd = mpCurrAnchoredObj
                            ? mpCurrAnchoredObj->GetDrawObj()->GetOrdNum()
                            : SAL_MAX_UINT32;
    OSL_ENSURE( !m_bTopRule, "DrawTextOpaque: Wrong TopRule" );

    // #i68520#
    const SwAnchoredObjList::size_type nCount( m_bOn ? GetAnchoredObjList().size() : 0 );
    if (nCount > 0)
    {
        const SdrLayerID nHellId = m_pPage->getRootFrame()->GetCurrShell()->getIDocumentDrawModelAccess().GetHellId();
        for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
        {
            // #i68520#
            const SwAnchoredObject* pTmpAnchoredObj = (*mpAnchoredObjList)[i];
            const SwFlyFrame* pFly = pTmpAnchoredObj->DynCastFlyFrame();
            if( pFly && mpCurrAnchoredObj != pTmpAnchoredObj )
            {
                // #i68520#
                if( aRegion.GetOrigin().Overlaps( pFly->getFrameArea() ) )
                {
                    const SwFrameFormat *pFormat = pFly->GetFormat();
                    const SwFormatSurround &rSur = pFormat->GetSurround();
                    const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
                    // Only the ones who are opaque and more to the top
                    if( ! pFly->IsBackgroundTransparent() &&
                        css::text::WrapTextMode_THROUGH == rSur.GetSurround() &&
                        ( !rSur.IsAnchorOnly() ||
                          // #i68520#
                          GetMaster() == pFly->GetAnchorFrame() ||
                          ((RndStdIds::FLY_AT_PARA != rAnchor.GetAnchorId()) &&
                           (RndStdIds::FLY_AT_CHAR != rAnchor.GetAnchorId())
                          )
                        ) &&
                        // #i68520#
                        pTmpAnchoredObj->GetDrawObj()->GetLayer() != nHellId &&
                        nCurrOrd < pTmpAnchoredObj->GetDrawObj()->GetOrdNum()
                      )
                    {
                        // Except for the content is transparent
                        const SwNoTextFrame *pNoText =
                                pFly->Lower() && pFly->Lower()->IsNoTextFrame()
                                                   ? static_cast<const SwNoTextFrame*>(pFly->Lower())
                                                   : nullptr;
                        if ( !pNoText ||
                             (!pNoText->IsTransparent() && !rSur.IsContour()) )
                        {
                            bOpaque = true;
                            aRegion -= pFly->getFrameArea();
                        }
                    }
                }
            }
        }
    }

    Point aPos( rInf.GetPos().X(), rInf.GetPos().Y() + rInf.GetAscent() );
    const Point aOldPos(rInf.GetPos());
    rInf.SetPos( aPos );

    if( !bOpaque )
    {
        if( rInf.GetKern() )
            rInf.GetFont()->DrawStretchText_( rInf );
        else
            rInf.GetFont()->DrawText_( rInf );
        rInf.SetPos(aOldPos);
        return;
    }
    else if( !aRegion.empty() )
    {
        // What a huge effort ...
        SwSaveClip aClipVout( rInf.GetpOut() );
        for( size_t i = 0; i < aRegion.size(); ++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(aOldPos);
}

void SwTextFly::DrawFlyRect( OutputDevice* pOut, const SwRect &rRect )
{
    SwRegionRects aRegion( rRect );
    OSL_ENSURE( !m_bTopRule, "DrawFlyRect: Wrong TopRule" );
    // #i68520#
    const SwAnchoredObjList::size_type nCount( m_bOn ? GetAnchoredObjList().size() : 0 );
    if (nCount > 0)
    {
        const SdrLayerID nHellId = m_pPage->getRootFrame()->GetCurrShell()->getIDocumentDrawModelAccess().GetHellId();
        for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
        {
            // #i68520#
            const SwAnchoredObject* pAnchoredObjTmp = (*mpAnchoredObjList)[i];
            if (mpCurrAnchoredObj == pAnchoredObjTmp)
                continue;

            // #i68520#
            const SwFlyFrame* pFly = pAnchoredObjTmp->DynCastFlyFrame();
            if (pFly)
            {
                // #i68520#
                const SwFormatSurround& rSur = pAnchoredObjTmp->GetFrameFormat()->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
                // #i47804# - consider transparent graphics
                // and OLE objects.
                const SwFrame* pLower = pFly->Lower();
                bool bClipFlyArea =
                        ( ( css::text::WrapTextMode_THROUGH == rSur.GetSurround() )
                          // #i68520#
                          ? (pAnchoredObjTmp->GetDrawObj()->GetLayer() != nHellId)
                          : !rSur.IsContour() ) &&
                        !pFly->IsBackgroundTransparent() &&
                        ( !pLower ||
                          !pLower->IsNoTextFrame() ||
                          !static_cast<const SwNoTextFrame*>(pLower)->IsTransparent() );
                if ( bClipFlyArea )
                {
                    // #i68520#
                    SwRect aFly( pAnchoredObjTmp->GetObjRect() );
                    // OD 24.01.2003 #106593#
                    ::SwAlignRect( aFly, m_pPage->getRootFrame()->GetCurrShell(), pOut );
                    if( !aFly.IsEmpty() )
                        aRegion -= aFly;
                }
            }
        }
    }

    for( size_t i = 0; i < aRegion.size(); ++i )
    {
        pOut->DrawRect( aRegion[i].SVRect() );
    }
}

/**
 * #i26945# - change first parameter
 * Now it's the <SwAnchoredObject> instance of the floating screen object
 */

bool SwTextFly::GetTop( const SwAnchoredObject* _pAnchoredObj,
                       const bool bInFootnote,
                       const bool bInFooterOrHeader )
{
    // #i68520#
    // <mpCurrAnchoredObj> is set, if <m_pCurrFrame> is inside a fly frame
    if( _pAnchoredObj != mpCurrAnchoredObj )
    {
        // #i26945#
        const SdrObject* pNew = _pAnchoredObj->GetDrawObj();
        // #102344# Ignore connectors which have one or more connections
        if (const SdrEdgeObj* pEdgeObj = dynamic_cast<const SdrEdgeObj*>(pNew))
        {
            if (pEdgeObj->GetConnectedNode(true) || pEdgeObj->GetConnectedNode(false))
            {
                return false;
            }
        }

        if( ( bInFootnote || bInFooterOrHeader ) && m_bTopRule )
        {
            // #i26945#
            const SwFrameFormat* pFrameFormat = _pAnchoredObj->GetFrameFormat();
            const SwFormatAnchor& rNewA = pFrameFormat->GetAnchor();
            if (RndStdIds::FLY_AT_PAGE == rNewA.GetAnchorId())
            {
                if ( bInFootnote )
                    return false;

                if ( bInFooterOrHeader )
                {
                    const SwFormatVertOrient& aVert(pFrameFormat->GetVertOrient());
                    bool bVertPrt = aVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ||
                            aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA;
                    if( bVertPrt )
                        return false;
                }
            }
        }

        // #i68520#
        // bEvade: consider pNew, if we are not inside a fly
        //         consider pNew, if pNew is lower of <mpCurrAnchoredObj>
        bool bEvade = !mpCurrAnchoredObj ||
                          Is_Lower_Of( mpCurrAnchoredObj->DynCastFlyFrame(), pNew);

        auto pFly = _pAnchoredObj->DynCastFlyFrame();
        if (pFly && pFly->IsFlySplitAllowed())
        {
            // Check if _pAnchoredObj is a split fly inside an other split fly. Always collect such
            // flys, otherwise the inner anchor text will overlap with the inner fly.
            SwFrame* pFlyAnchor = const_cast<SwAnchoredObject*>(_pAnchoredObj)
                ->GetAnchorFrameContainingAnchPos();
            if (pFlyAnchor && pFlyAnchor->IsInFly())
            {
                auto pOuterFly = pFlyAnchor->FindFlyFrame();
                if (pOuterFly && pOuterFly->IsFlySplitAllowed())
                {
                    return true;
                }
            }
        }

        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 ( !m_bTopRule )
                bEvade = true;
            else
            {
                // Within chained Flys we only avoid Lower
                // #i68520#
                const SwFrameFormat* pCurObjFormat = mpCurrAnchoredObj->GetFrameFormat();
                const SwFormatChain& rChain = pCurObjFormat->GetChain();
                if ( !rChain.GetPrev() && !rChain.GetNext() )
                {
                    // #i26945#
                    const SwFormatAnchor& rNewA = _pAnchoredObj->GetFrameFormat()->GetAnchor();
                    // #i68520#
                    const SwFormatAnchor& rCurrA = pCurObjFormat->GetAnchor();

                    // If <mpCurrAnchoredObj> is anchored as character, its content
                    // does not wrap around pNew
                    if (RndStdIds::FLY_AS_CHAR == rCurrA.GetAnchorId())
                        return 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 (RndStdIds::FLY_AT_PAGE == rNewA.GetAnchorId())
                    {
                        if (RndStdIds::FLY_AT_PAGE == rCurrA.GetAnchorId())
                        {
                            bEvade = true;
                        }
                        else
                            return false;
                    }
                    else if (RndStdIds::FLY_AT_PAGE == rCurrA.GetAnchorId())
                        return false// Page anchored ones only avoid page anchored ones
                    else if (RndStdIds::FLY_AT_FLY == rNewA.GetAnchorId())
                        bEvade = true// Non-page anchored ones avoid frame anchored ones
                    else if( RndStdIds::FLY_AT_FLY == rCurrA.GetAnchorId() )
                        return false// Frame anchored ones do not avoid paragraph anchored ones
                    // #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
                        return false;
                }
            }

            // But: we never avoid a subordinate one and additionally we only avoid when overlapping.
            // #i68520#
            bEvade &= ( mpCurrAnchoredObj->GetDrawObj()->GetOrdNum() < pNew->GetOrdNum() );
            if( bEvade )
            {
                // #i68520#
                const SwRect& aTmp( _pAnchoredObj->GetObjRectWithSpaces() );
                if ( !aTmp.Overlaps( mpCurrAnchoredObj->GetObjRectWithSpaces() ) )
                    bEvade = false;
            }
        }

        if ( bEvade )
        {
            // #i26945#
            if (const SwFrameFormat* pAnchoredObjFormat = _pAnchoredObj->GetFrameFormat())
            {
                const SwFormatAnchor& rNewA = pAnchoredObjFormat->GetAnchor();
                OSL_ENSURE(RndStdIds::FLY_AS_CHAR != rNewA.GetAnchorId(),
                           "Don't call GetTop with a FlyInContentFrame");
                if (RndStdIds::FLY_AT_PAGE == rNewA.GetAnchorId())
                    return true// We always avoid page anchored ones

                // If Flys anchored at paragraph are caught in a FlyCnt, then
                // their influence ends at the borders of the FlyCnt!
                // If we are currently formatting the text of the FlyCnt, then
                // it has to get out of the way of the Frame anchored at paragraph!
                // m_pCurrFrame is the anchor of pNew?
                // #i26945#
                const SwFrame* pTmp = _pAnchoredObj->GetAnchorFrame();
                if (pTmp == m_pCurrFrame)
                    return true;
                if (pTmp->IsTextFrame() && (pTmp->IsInFly() || pTmp->IsInFootnote()))
                {
                    // #i26945#
                    Point aPos = _pAnchoredObj->GetObjRect().Pos();
                    pTmp = GetVirtualUpper(pTmp, aPos);
                }
                // #i26945#
                // If <pTmp> is a text frame inside a table, take the upper
                // of the anchor frame, which contains the anchor position.
                else if (pTmp->IsTextFrame() && pTmp->IsInTab())
                {
                    pTmp = const_cast<SwAnchoredObject*>(_pAnchoredObj)
                               ->GetAnchorFrameContainingAnchPos()
                               ->GetUpper();
                }
                // #i28701# - consider all objects in same context,
                // if wrapping style is considered on object positioning.
                // Thus, text will wrap around negative positioned objects.
                // #i3317# - remove condition on checking,
                // if wrappings style is considered on object positioning.
                // Thus, text is wrapping around negative positioned objects.
                // #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
                    = &m_pCurrFrame->GetDoc().getIDocumentSettingAccess();
                if ((pIDSA->get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION)
                     || !pIDSA->get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING))
                    && ::FindContext(pTmp, SwFrameType::None)
                           == ::FindContext(m_pCurrFrame, SwFrameType::None))
                {
                    return true;
                }

                const SwFrame* pHeader = nullptr;
                if (m_pCurrFrame->GetNext() != pTmp
                    && (IsFrameInSameContext(pTmp, m_pCurrFrame) ||
                        // #i13832#, #i24135# wrap around objects in page header
                        (!pIDSA->get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING)
                         && nullptr != (pHeader = pTmp->FindFooterOrHeader())
                         && m_pCurrFrame->IsInDocBody())))
                {
                    if (pHeader || RndStdIds::FLY_AT_FLY == rNewA.GetAnchorId())
                        return true;

                    // Compare indices:
                    // The Index of the other is retrieved from the anchor attr.
                    SwNodeOffset nTmpIndex = rNewA.GetAnchorNode()->GetIndex();
                    // Now check whether the current paragraph is before the anchor
                    // of the displaced object in the text, then we don't have to
                    // get out of its way.
                    // If possible determine Index via SwFormatAnchor because
                    // otherwise it's quite expensive.
                    if (NODE_OFFSET_MAX == m_nCurrFrameNodeIndex)
                        m_nCurrFrameNodeIndex = m_pCurrFrame->GetTextNodeFirst()->GetIndex();

                    if (FrameContainsNode(*m_pCurrFrame, nTmpIndex)
                        || nTmpIndex < m_nCurrFrameNodeIndex)
                        return true;
                }
            }
        }
    }
    return false;
}

SwRect SwTextFly::GetFrameArea() const
{
    // i#28701 - consider complete frame area for new text wrapping
    SwRect aRect;
    if (m_pCurrFrame->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING))
    {
        aRect = m_pCurrFrame->getFramePrintArea();
        aRect += m_pCurrFrame->getFrameArea().Pos();
    }
    else
    {
        aRect = m_pCurrFrame->getFrameArea();
    }
    return aRect;
}

// #i68520#
SwAnchoredObjList& SwTextFly::InitAnchoredObjList()
{
    OSL_ENSURE( m_pCurrFrame, "InitFlyList: No Frame, no FlyList" );
    // #i68520#
    OSL_ENSURE( !mpAnchoredObjList, "InitFlyList: FlyList already initialized" );

    SwSwapIfSwapped swap(const_cast<SwTextFrame *>(m_pCurrFrame));

    const SwSortedObjs *pSorted = m_pPage->GetSortedObjs();
    const size_t nCount = pSorted ? pSorted->size() : 0;
    // --> #108724# Page header/footer content doesn't have to wrap around
    //              floating screen objects
    //              which was added simply to be compatible with MS Office.
    // MSO still allows text to wrap around in-table-flies in headers/footers/footnotes
    const bool bFooterHeader = nullptr != m_pCurrFrame->FindFooterOrHeader();
    const IDocumentSettingAccess* pIDSA = &m_pCurrFrame->GetDoc().getIDocumentSettingAccess();
    // #i40155# - check, if frame is marked not to wrap
    const bool bAllowCompatWrap = m_pCurrFrame->IsInTab() && (bFooterHeader || m_pCurrFrame->IsInFootnote());
    const bool bWrapAllowed = ( pIDSA->get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING) ||
                                    bAllowCompatWrap ||
                                    (!m_pCurrFrame->IsInFootnote() && !bFooterHeader));

    m_bOn = false;

    // #i68520#
    mpAnchoredObjList.reset(new SwAnchoredObjList);

    if( nCount && bWrapAllowed )
    {
        SwRect const aRect(GetFrameArea());
        // Make ourselves a little smaller than we are,
        // so that 1-Twip-overlappings are ignored (#49532)
        SwRectFnSet aRectFnSet(m_pCurrFrame);
        const tools::Long nRight = aRectFnSet.GetRight(aRect) - 1;
        const tools::Long nLeft = aRectFnSet.GetLeft(aRect) + 1;
        const bool bR2L = m_pCurrFrame->IsRightToLeft();

        const IDocumentDrawModelAccess& rIDDMA = m_pCurrFrame->GetDoc().getIDocumentDrawModelAccess();

        for( size_t i = 0; i < nCount; ++i )
        {
            // #i68520#
            // do not consider hidden objects
            // check, if object has to be considered for text wrap
            // #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 <SwTextFrame::CalcBaseOfstForFly()>
            // #i20505# Do not consider oversized objects
            SwAnchoredObject* pAnchoredObj = (*pSorted)[ i ];
            assert(pAnchoredObj);
            if ( !pAnchoredObj ||
                 !rIDDMA.IsVisibleLayerId( pAnchoredObj->GetDrawObj()->GetLayer() ) ||
                 !pAnchoredObj->ConsiderForTextWrap() ||
                 ( mbIgnoreObjsInHeaderFooter && !bFooterHeader &&
                   pAnchoredObj->GetAnchorFrame()->FindFooterOrHeader() ) ||
                 ( bAllowCompatWrap && !pAnchoredObj->GetFrameFormat()->GetFollowTextFlow().GetValue() )
               )
            {
                continue;
            }

            const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
            if ( nRight < aRectFnSet.GetLeft(aBound) ||
                 aRectFnSet.YDiff( aRectFnSet.GetTop(aRect),
                                     aRectFnSet.GetBottom(aBound) ) > 0 ||
                 nLeft > aRectFnSet.GetRight(aBound) ||
                 aRectFnSet.GetHeight(aBound) >
                                    2 * aRectFnSet.GetHeight(m_pPage->getFrameArea()) )
            {
                continue;
            }

            // #i26945# - pass <pAnchoredObj> to method
            // <GetTop(..)> instead of only the <SdrObject> instance of the
            // anchored object
            if (GetTop(pAnchoredObj, m_pCurrFrame->IsInFootnote(), 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.
                // #i68520#
                {
                    SwAnchoredObjList::iterator aInsPosIter =
                            std::lower_bound( mpAnchoredObjList->begin(),
                                              mpAnchoredObjList->end(),
                                              pAnchoredObj,
                                              AnchoredObjOrder( bR2L, aRectFnSet.FnRect() ) );

                    mpAnchoredObjList->insert( aInsPosIter, pAnchoredObj );
                }

                const SwFrameFormat* pObjFormat = pAnchoredObj->GetFrameFormat();
                const SwFormatSurround& rFlyFormat = pObjFormat->GetSurround();
                // #i68520#
                if ( rFlyFormat.IsAnchorOnly() &&
                     pAnchoredObj->GetAnchorFrame() == GetMaster() )
                {
                    const SwFormatVertOrient &rTmpFormat = pObjFormat->GetVertOrient();
                    if( text::VertOrientation::BOTTOM != rTmpFormat.GetVertOrient() )
                        m_nMinBottom = ( aRectFnSet.IsVert() && m_nMinBottom ) ?
                                     std::min( m_nMinBottom, aBound.Left() ) :
                                     std::max( m_nMinBottom, aRectFnSet.GetBottom(aBound) );
                }

                m_bOn = true;
            }
        }
        if( m_nMinBottom )
        {
            SwTwips nMax = aRectFnSet.GetPrtBottom(*m_pCurrFrame->GetUpper());
            if( aRectFnSet.YDiff( m_nMinBottom, nMax ) > 0 )
                m_nMinBottom = nMax;
        }
    }

    // #i68520#
    return *mpAnchoredObjList;
}

SwTwips SwTextFly::CalcMinBottom() const
{
    SwTwips nRet = 0;
    const SwContentFrame *pLclMaster = GetMaster();
    OSL_ENSURE(pLclMaster, "SwTextFly without master");
    const SwSortedObjs *pDrawObj = pLclMaster ? pLclMaster->GetDrawObjs() : nullptr;
    const size_t nCount = pDrawObj ? pDrawObj->size() : 0;
    if( nCount )
    {
        SwTwips nEndOfFrame = m_pCurrFrame->getFrameArea().Bottom();
        for( size_t i = 0; i < nCount; ++i )
        {
            SwAnchoredObject* pAnchoredObj = (*pDrawObj)[ i ];
            const SwFrameFormat* pObjFormat = pAnchoredObj->GetFrameFormat();
            const SwFormatSurround& rFlyFormat = pObjFormat->GetSurround();
            if( rFlyFormat.IsAnchorOnly() )
            {
                const SwFormatVertOrient &rTmpFormat = pObjFormat->GetVertOrient();
                if( text::VertOrientation::BOTTOM != rTmpFormat.GetVertOrient() )
                {
                    const SwRect& aBound( pAnchoredObj->GetObjRectWithSpaces() );
                    if( aBound.Top() < nEndOfFrame )
                        nRet = std::max( nRet, SwTwips(aBound.Bottom()) );
                }
            }
        }
        SwTwips nMax = m_pCurrFrame->GetUpper()->getFrameArea().Top() +
                       m_pCurrFrame->GetUpper()->getFramePrintArea().Bottom();
        if( nRet > nMax )
            nRet = nMax;
    }
    return nRet;
}

SwTwips SwTextFly::GetMaxBottom(const SwBreakPortion& rPortion, const SwTextFormatInfo& rInfo) const
{
    // Note that m_pCurrFrame is already swapped at this stage, so it's correct to bypass
    // SwRectFnSet here.
    SwTwips nRet = 0;
    size_t nCount(m_bOn ? GetAnchoredObjList().size() : 0);

    // Get the horizontal position of the break portion in absolute twips. The frame area is in
    // absolute twips, the frame's print area is relative to the frame area. Finally the portion's
    // position is relative to the frame's print area.
    SwTwips nX = rInfo.X();
    nX += m_pCurrFrame->getFrameArea().Left();
    nX += m_pCurrFrame->getFramePrintArea().Left();

    for (size_t i = 0; i < nCount; ++i)
    {
        const SwAnchoredObject* pAnchoredObj = (*mpAnchoredObjList)[i];

        if (pAnchoredObj->GetAnchorFrame()->FindFooterOrHeader())
        {
            // Anchored in the header or footer, ignore it for clearing break purposes.
            continue;
        }

        const SwFormatSurround& rSurround = pAnchoredObj->GetFrameFormat()->GetSurround();
        if (rSurround.GetValue() == text::WrapTextMode_THROUGH)
        {
            // Wrap through has no influence on clearing breaks.
            continue;
        }

        SwRect aRect(pAnchoredObj->GetObjRectWithSpaces());

        if (m_pCurrFrame->IsVertical())
        {
            m_pCurrFrame->SwitchVerticalToHorizontal(aRect);
        }

        if (rPortion.GetClear() == SwLineBreakClear::LEFT)
        {
            if (nX < aRect.Left())
            {
                // Want to jump down to the first line that's unblocked on the left. This object is
                // on the right of the break, ignore it.
                continue;
            }
        }
        if (rPortion.GetClear() == SwLineBreakClear::RIGHT)
        {
            if (nX > aRect.Right())
            {
                // Want to jump down to the first line that's unblocked on the right. This object is
                // on the left of the break, ignore it.
                continue;
            }
        }
        SwTwips nBottom = aRect.Top() + aRect.Height();
        if (nBottom > nRet)
        {
            nRet = nBottom;
        }
    }
    return nRet;
}

bool SwTextFly::ForEach( const SwRect &rRect, SwRect* pRect, bool bAvoid ) const
{
    SwSwapIfSwapped swap(const_cast<SwTextFrame *>(m_pCurrFrame));

    // Optimization
    SwRectFnSet aRectFnSet(m_pCurrFrame);

    // tdf#127235 stop if the area is larger than the page
    if( aRectFnSet.GetHeight(m_pPage->getFrameArea()) < aRectFnSet.GetHeight(rRect))
    {
        // get the doc model description
        const SwPageDesc* pPageDesc = m_pPage->GetPageDesc();

        // if there is no next page style or it is the same as the current
        // => stop trying to place the frame (it would end in an infinite loop)
        if( pPageDesc &&
            ( !pPageDesc->GetFollow() || pPageDesc->GetFollow() == pPageDesc) )
        {
            return false;
        }
    }

    bool bRet = false;
    // #i68520#
    const SwAnchoredObjList::size_type nCount( m_bOn ? GetAnchoredObjList().size() : 0 );
    if (nCount > 0)
    {
        for( SwAnchoredObjList::size_type i = 0; i < nCount; ++i )
        {
            // #i68520#
            const SwAnchoredObject* pAnchoredObj = (*mpAnchoredObjList)[i];

            SwRect aRect( pAnchoredObj->GetObjRectWithSpaces() );

            if( aRectFnSet.GetLeft(aRect) > aRectFnSet.GetRight(rRect) )
                break;

            // #i68520#
            if ( mpCurrAnchoredObj != pAnchoredObj && aRect.Overlaps( rRect ) )
            {
                // #i68520#
                const SwFormat* pFormat(pAnchoredObj->GetFrameFormat());
                const SwFormatSurround &rSur = pFormat->GetSurround();
                if( bAvoid )
                {
                    // If the text flows below, it has no influence on
                    // formatting. In LineIter::DrawText() it is "just"
                    // necessary to cleverly set the ClippingRegions
                    const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
                    if( ( css::text::WrapTextMode_THROUGH == rSur.GetSurround() &&
                          ( !rSur.IsAnchorOnly() ||
                            // #i68520#
                            GetMaster() == pAnchoredObj->GetAnchorFrame() ||
                            ((RndStdIds::FLY_AT_PARA != rAnchor.GetAnchorId()) &&
                             (RndStdIds::FLY_AT_CHAR != rAnchor.GetAnchorId())) ) )
                        || aRect.Top() == FAR_AWAY )
                        continue;
                }

                // #i58642#
                // Compare <GetMaster()> instead of <m_pCurrFrame> with the
                // anchor frame of the anchored object, because a follow frame
                // has 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.
                // #i68520#
                if ( mbIgnoreCurrentFrame &&
                     GetMaster() == pAnchoredObj->GetAnchorFrame() )
                    continue;

                if( pRect )
                {
                    // #i68520#
                    SwRect aFly = AnchoredObjToRect( pAnchoredObj, rRect );
                    if( aFly.IsEmpty() || !aFly.Overlaps( rRect ) )
                        continue;
                    if( !bRet || (
                        (!m_pCurrFrame->IsRightToLeft() &&
                          ( aRectFnSet.GetLeft(aFly) <
                            aRectFnSet.GetLeft(*pRect) ) ) ||
                        (m_pCurrFrame->IsRightToLeft() &&
                          ( aRectFnSet.GetRight(aFly) >
                            aRectFnSet.GetRight(*pRect) ) ) ) )
                        *pRect = aFly;
                    if( rSur.IsContour() )
                    {
                        bRet = true;
                        continue;
                    }
                }
                bRet = true;
                break;
            }
        }
    }

    return bRet;
}

// #i68520#
SwAnchoredObjList::size_type SwTextFly::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;
}

// #i68520#
void SwTextFly::CalcRightMargin( SwRect &rFly,
                                SwAnchoredObjList::size_type nFlyPos,
                                const SwRect &rLine ) const
{
    // Usually the right margin is the right margin of the Printarea
    OSL_ENSURE( !m_pCurrFrame->IsVertical() || !m_pCurrFrame->IsSwapped(),
            "SwTextFly::CalcRightMargin with swapped frame" );
    SwRectFnSet aRectFnSet(m_pCurrFrame);
    // #118796# - correct determination of right of printing area
    SwTwips nRight = aRectFnSet.GetPrtRight(*m_pCurrFrame);
    SwTwips nFlyRight = aRectFnSet.GetRight(rFly);
    SwRect aLine( rLine );
    aRectFnSet.SetRight( aLine, nRight );
    aRectFnSet.SetLeft( aLine, aRectFnSet.GetLeft(rFly) );

    // It is possible that there is another object that is _above_ us
    // and protrudes into the same line.
    // Flys with run-through are invisible for those below, i.e., they
    // are ignored for computing the margins of other Flys.
    // 3301: pNext->getFrameArea().Overlaps( rLine ) is necessary
    // #i68520#
    css::text::WrapTextMode eSurroundForTextWrap;

    bool bStop = false;
    // #i68520#
    SwAnchoredObjList::size_type nPos = 0;

    // #i68520#
    while( nPos < mpAnchoredObjList->size() && !bStop )
    {
        if( nPos == nFlyPos )
        {
            ++nPos;
            continue;
        }
        // #i68520#
        const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nPos++ ];
        if ( pNext == mpCurrAnchoredObj )
            continue;
        eSurroundForTextWrap = GetSurroundForTextWrap( pNext );
        if( css::text::WrapTextMode_THROUGH == eSurroundForTextWrap )
            continue;

        const SwRect aTmp( SwContourCache::CalcBoundRect
                ( pNext, aLine, m_pCurrFrame, nFlyRight, true ) );
        SwTwips nTmpRight = aRectFnSet.GetRight(aTmp);

        // optimization:
        // Record in nNextTop at which Y-position frame related changes are
        // likely.  This is so that, despite only looking at frames in the
        // current line height, for frames without wrap the line height is
        // incremented so that with a single line the lower border of the frame
        // (or possibly the upper border of another frame) is reached.
        // Especially in HTML documents there are often (dummy) paragraphs in
        // 2 pt font, and they used to only evade big frames after huge numbers
        // of empty lines.
        const tools::Long nTmpTop = aRectFnSet.GetTop(aTmp);
        if( aRectFnSet.YDiff( nTmpTop, aRectFnSet.GetTop(aLine) ) > 0 )
        {
            if( aRectFnSet.YDiff( m_nNextTop, nTmpTop ) > 0 )
                SetNextTop( nTmpTop ); // upper border of next frame
        }
        else if (!aRectFnSet.GetWidth(aTmp)) // typical for Objects with contour wrap
        {   // For Objects with contour wrap that start before the current
            // line, and end below it, but do not actually overlap it, the
            // optimization has to be disabled, because the circumstances
            // can change in the next line.
            if( ! aRectFnSet.GetHeight(aTmp) ||
                aRectFnSet.YDiff( aRectFnSet.GetBottom(aTmp),
                                    aRectFnSet.GetTop(aLine) ) > 0 )
                SetNextTop( 0 );
        }
        if( aTmp.Overlaps( aLine ) && nTmpRight > nFlyRight )
        {
            nFlyRight = nTmpRight;
            if( css::text::WrapTextMode_RIGHT == eSurroundForTextWrap ||
                css::text::WrapTextMode_PARALLEL == eSurroundForTextWrap )
            {
                // overrule the FlyFrame
                if( nRight > nFlyRight )
                    nRight = nFlyRight;
                bStop = true;
            }
        }
    }
    aRectFnSet.SetRight( rFly, nRight );
}

// #i68520#
void SwTextFly::CalcLeftMargin( SwRect &rFly,
                               SwAnchoredObjList::size_type nFlyPos,
                               const SwRect &rLine ) const
{
    OSL_ENSURE( !m_pCurrFrame->IsVertical() || !m_pCurrFrame->IsSwapped(),
            "SwTextFly::CalcLeftMargin with swapped frame" );
    SwRectFnSet aRectFnSet(m_pCurrFrame);
    // #118796# - correct determination of left of printing area
    SwTwips nLeft = aRectFnSet.GetPrtLeft(*m_pCurrFrame);
    const SwTwips nFlyLeft = aRectFnSet.GetLeft(rFly);

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

    SwRect aLine( rLine );
    aRectFnSet.SetLeft( aLine, nLeft );

    // It is possible that there is another object that is _above_ us
    // and protrudes into the same line.
    // Flys with run-through are invisible for those below, i.e., they
    // are ignored for computing the margins of other Flys.
    // 3301: pNext->getFrameArea().Overlaps( rLine ) is necessary

    // #i68520#
    SwAnchoredObjList::size_type nMyPos = nFlyPos;
    while( ++nFlyPos < mpAnchoredObjList->size() )
    {
        // #i68520#
        const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
        const SwRect& aTmp( pNext->GetObjRectWithSpaces() );
        if( aRectFnSet.GetLeft(aTmp) >= nFlyLeft )
            break;
    }

    while( nFlyPos )
    {
        if( --nFlyPos == nMyPos )
            continue;
        // #i68520#
        const SwAnchoredObject* pNext = (*mpAnchoredObjList)[ nFlyPos ];
        if( pNext == mpCurrAnchoredObj )
            continue;
        css::text::WrapTextMode eSurroundForTextWrap = GetSurroundForTextWrap( pNext );
        if( css::text::WrapTextMode_THROUGH == eSurroundForTextWrap )
            continue;

        const SwRect aTmp( SwContourCache::CalcBoundRect
                (pNext, aLine, m_pCurrFrame, nFlyLeft, false) );

        if( aRectFnSet.GetLeft(aTmp) < nFlyLeft && aTmp.Overlaps( aLine ) )
        {
            // #118796# - no '+1', because <..fnGetRight>
            // returns the correct value.
            SwTwips nTmpRight = aRectFnSet.GetRight(aTmp);
            if ( nLeft <= nTmpRight )
                nLeft = nTmpRight;

            break;
        }
    }
    aRectFnSet.SetLeft( rFly, nLeft );
}

// #i68520#
SwRect SwTextFly::AnchoredObjToRect( const SwAnchoredObject* pAnchoredObj,
                            const SwRect &rLine ) const
{
    SwRectFnSet aRectFnSet(m_pCurrFrame);

    const tools::Long nXPos = m_pCurrFrame->IsRightToLeft() ?
                       rLine.Right() :
                       aRectFnSet.GetLeft(rLine);

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

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

    // so the line may grow up to the lower edge of the frame
    SetNextTop( aRectFnSet.GetBottom(aFly) );
    SwAnchoredObjList::size_type nFlyPos = GetPos( pAnchoredObj );

    // LEFT and RIGHT, we grow the rectangle.
    // We have some problems, when several frames are to be seen.
    // At the moment, only the easier case is assumed:
    //  + LEFT means that the text must flow on the left of the frame,
    //    that is the frame expands to the right edge of the print area
    //    or to the next frame.
    //  + RIGHT is the opposite.
    // Otherwise the set distance between text and frame is always
    // added up.
    switch( GetSurroundForTextWrap( pAnchoredObj ) )
    {
        case css::text::WrapTextMode_LEFT :
        {
            CalcRightMargin( aFly, nFlyPos, rLine );
            break;
        }
        case css::text::WrapTextMode_RIGHT :
        {
            CalcLeftMargin( aFly, nFlyPos, rLine );
            break;
        }
        case css::text::WrapTextMode_NONE :
        {
            CalcRightMargin( aFly, nFlyPos, rLine );
            CalcLeftMargin( aFly, nFlyPos, rLine );
            break;
        }
        default:
            break;
    }
    return aFly;
}

// #i68520#

// Wrap only on sides with at least 2cm space for the text
#define TEXT_MIN 1134

// Wrap on both sides up to a frame width of 1.5cm
#define FRAME_MAX 850

css::text::WrapTextMode SwTextFly::GetSurroundForTextWrap( const SwAnchoredObject* pAnchoredObj ) const
{
    const SwFrameFormat* pFormat = pAnchoredObj->GetFrameFormat();
    const SwFormatSurround &rFlyFormat = pFormat->GetSurround();
    css::text::WrapTextMode eSurroundForTextWrap = rFlyFormat.GetSurround();

    if( rFlyFormat.IsAnchorOnly() && pAnchoredObj->GetAnchorFrame() != GetMaster() )
    {
        const SwFormatAnchor& rAnchor = pFormat->GetAnchor();
        if ((RndStdIds::FLY_AT_PARA == rAnchor.GetAnchorId()) ||
            (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId()))
        {
            return css::text::WrapTextMode_NONE;
        }
    }

    // in cause of run-through and nowrap ignore smartly
    if( css::text::WrapTextMode_THROUGH == eSurroundForTextWrap ||
        css::text::WrapTextMode_NONE == eSurroundForTextWrap )
        return eSurroundForTextWrap;

    // left is left and right is right
    if (m_pCurrFrame->IsRightToLeft())
    {
        if ( css::text::WrapTextMode_LEFT == eSurroundForTextWrap )
            eSurroundForTextWrap = css::text::WrapTextMode_RIGHT;
        else if ( css::text::WrapTextMode_RIGHT == eSurroundForTextWrap )
            eSurroundForTextWrap = css::text::WrapTextMode_LEFT;
    }

    // "ideal page wrap":
    if ( css::text::WrapTextMode_DYNAMIC == eSurroundForTextWrap )
    {
        SwRectFnSet aRectFnSet(m_pCurrFrame);
        const tools::Long nCurrLeft = aRectFnSet.GetPrtLeft(*m_pCurrFrame);
        const tools::Long nCurrRight = aRectFnSet.GetPrtRight(*m_pCurrFrame);
        const SwRect& aRect( pAnchoredObj->GetObjRectWithSpaces() );
        tools::Long nFlyLeft = aRectFnSet.GetLeft(aRect);
        tools::Long nFlyRight = aRectFnSet.GetRight(aRect);

        if ( nFlyRight < nCurrLeft || nFlyLeft > nCurrRight )
            eSurroundForTextWrap = css::text::WrapTextMode_PARALLEL;
        else
        {
            tools::Long nLeft = nFlyLeft - nCurrLeft;
            tools::Long nRight = nCurrRight - nFlyRight;
            if( nFlyRight - nFlyLeft > FRAME_MAX )
            {
                if( nLeft < nRight )
                    nLeft = 0;
                else
                    nRight = 0;
            }
            const int textMin = GetMaster()->GetDoc()
                .getIDocumentSettingAccess().get(DocumentSettingId::SURROUND_TEXT_WRAP_SMALL )
                ? TEXT_MIN_SMALL : TEXT_MIN;

            // In case there is no space on either side, then css::text::WrapTextMode_PARALLEL
            // gives the same result when doing the initial layout or a layout
            // update after editing, so prefer that over css::text::WrapTextMode_NONE.
            if (nLeft == 0 && nRight == 0)
                return css::text::WrapTextMode_PARALLEL;

            if( nLeft < textMin )
                nLeft = 0;
            if( nRight < textMin )
                nRight = 0;
            if( nLeft )
                eSurroundForTextWrap = nRight ? css::text::WrapTextMode_PARALLEL : css::text::WrapTextMode_LEFT;
            else
                eSurroundForTextWrap = nRight ? css::text::WrapTextMode_RIGHT: css::text::WrapTextMode_NONE;
        }
    }

    return eSurroundForTextWrap;
}

bool SwTextFly::IsAnyFrame( const SwRect &rLine ) const
{

    SwSwapIfSwapped swap(const_cast<SwTextFrame *>(m_pCurrFrame));

    OSL_ENSURE( m_bOn, "IsAnyFrame: Why?" );

    return ForEach( rLine, nullptr, false );
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=84 H=94 G=88

¤ Dauer der Verarbeitung: 0.38 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.