    /* -*- 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 <pagefrm.hxx>
    #include <rootfrm.hxx>
    #include <IDocumentFieldsAccess.hxx>
    #include <viewimp.hxx>
    #include <fesh.hxx>
    #include <swtable.hxx>
    #include <dflyobj.hxx>
    #include <anchoreddrawobject.hxx>
    #include <fmtanchr.hxx>
    #include <viewopt.hxx>
    #include <hints.hxx>
    #include <dbg_lay.hxx>
    #include <ftnidx.hxx>
    #include <svl/itemiter.hxx>
    #include <editeng/keepitem.hxx>
    #include <editeng/ulspitem.hxx>
    #include <editeng/brushitem.hxx>
    #include <editeng/boxitem.hxx>
    #include <fmtlsplt.hxx>
    #include <fmtrowsplt.hxx>
    #include <fmtsrnd.hxx>
    #include <fmtornt.hxx>
    #include <fmtpdsc.hxx>
    #include <fmtfsize.hxx>
    #include <swtblfmt.hxx>
    #include <tabfrm.hxx>
    #include <rowfrm.hxx>
    #include <cellfrm.hxx>
    #include <flyfrms.hxx>
    #include <txtfrm.hxx>
    #include <notxtfrm.hxx>
    #include <htmltbl.hxx>
    #include <sectfrm.hxx>
    #include <fmtfollowtextflow.hxx>
    #include <sortedobjs.hxx>
    #include <objectformatter.hxx>
    #include <layouter.hxx>
    #include <calbck.hxx>
    #include <DocumentSettingManager.hxx>
    #include <docary.hxx>
    #include <o3tl/make_unique.hxx>
    #include <sal/log.hxx>

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

    SwTabFrame::SwTabFrame( SwTable &rTab, SwFrame* pSib )
        : SwLayoutFrame( rTab.GetFrameFormat(), pSib )
        , SwFlowFrame( static_cast<SwFrame&>(*this) )
        , m_pTable( &rTab )
        , m_bComplete(false)
        , m_bCalcLowers(false)
        , m_bLowersFormatted(false)
        , m_bLockBackMove(false)
        , m_bResizeHTMLTable(false)
        , m_bONECalcLowers(false)
        , m_bHasFollowFlowLine(false)
        , m_bIsRebuildLastLine(false)
        , m_bRestrictTableGrowth(false)
        , m_bRemoveFollowFlowLinePending(false)
        , m_bConsiderObjsForMinCellHeight(true)
        , m_bObjsDoesFit(true)
        , m_bInRecalcLowerRow(false)
    {
        mbFixSize = false;     //Don't fall for import filter again.
        mnFrameType = SwFrameType::Tab;

        //Create the lines and insert them.
        const SwTableLines &rLines = rTab.GetTabLines();
        SwFrame *pTmpPrev = nullptr;
        for ( size_t i = 0; i < rLines.size(); ++i )
        {
            SwRowFrame *pNew = new SwRowFrame( *rLines[i], this );
            if( pNew->Lower() )
            {
                pNew->InsertBehind( this, pTmpPrev );
                pTmpPrev = pNew;
            }
            else
                SwFrame::DestroyFrame(pNew);
        }
        OSL_ENSURE( Lower() && Lower()->IsRowFrame(), "SwTabFrame::SwTabFrame: No rows." );
    }

    SwTabFrame::SwTabFrame( SwTabFrame &rTab )
        : SwLayoutFrame( rTab.GetFormat(), &rTab )
        , SwFlowFrame( static_cast<SwFrame&>(*this) )
        , m_pTable( rTab.GetTable() )
        , m_bComplete(false)
        , m_bCalcLowers(false)
        , m_bLowersFormatted(false)
        , m_bLockBackMove(false)
        , m_bResizeHTMLTable(false)
        , m_bONECalcLowers(false)
        , m_bHasFollowFlowLine(false)
        , m_bIsRebuildLastLine(false)
        , m_bRestrictTableGrowth(false)
        , m_bRemoveFollowFlowLinePending(false)
        , m_bConsiderObjsForMinCellHeight(true)
        , m_bObjsDoesFit(true)
        , m_bInRecalcLowerRow(false)
    {
        mbFixSize = false;     //Don't fall for import filter again.
        mnFrameType = SwFrameType::Tab;

        SetFollow( rTab.GetFollow() );
        rTab.SetFollow( this );
    }

    void SwTabFrame::DestroyImpl()
    {
        // There is some terrible code in fetab.cxx, that
        // caches pointers to SwTabFrames.
        ::ClearFEShellTabCols(*GetFormat()->GetDoc(), this);

        SwLayoutFrame::DestroyImpl();
    }

    SwTabFrame::~SwTabFrame()
    {
    }

    void SwTabFrame::JoinAndDelFollows()
    {
        SwTabFrame *pFoll = GetFollow();
        if ( pFoll->HasFollow() )
            pFoll->JoinAndDelFollows();
        pFoll->Cut();
        SetFollow( pFoll->GetFollow() );
        SwFrame::DestroyFrame(pFoll);
    }

    void SwTabFrame::RegistFlys()
    {
        OSL_ENSURE( Lower() && Lower()->IsRowFrame(), "No rows." );

        SwPageFrame *pPage = FindPageFrame();
        if ( pPage )
        {
            SwRowFrame *pRow = static_cast<SwRowFrame*>(Lower());
            do
            {
                pRow->RegistFlys( pPage );
                pRow = static_cast<SwRowFrame*>(pRow->GetNext());
            } while ( pRow );
        }
    }

    void SwInvalidateAll( SwFrame *pFrame, long nBottom );
    static void lcl_RecalcRow( SwRowFrame* pRow, long nBottom );
    static bool lcl_ArrangeLowers( SwLayoutFrame *pLay, long lYStart, bool bInva );
    // #i26945# - add parameter <_bOnlyRowsAndCells> to control
    // that only row and cell frames are formatted.
    static bool lcl_InnerCalcLayout( SwFrame *pFrame,
                                          long nBottom,
                                          bool _bOnlyRowsAndCells = false );
    // OD 2004-02-18 #106629# - correct type of 1st parameter
    // #i26945# - add parameter <_bConsiderObjs> in order to
    // control, if floating screen objects have to be considered for the minimal
    // cell height.
    static SwTwips lcl_CalcMinRowHeight( const SwRowFrame *pRow,
                                         const bool _bConsiderObjs );
    static SwTwips lcl_CalcTopAndBottomMargin( const SwLayoutFrame&, const SwBorderAttrs& );

    static SwTwips lcl_calcHeightOfRowBeforeThisFrame(const SwRowFrame& rRow);

    static SwTwips lcl_GetHeightOfRows( const SwFrame* pStart, long nCount )
    {
        if ( !nCount || !pStart)
            return 0;

        SwTwips nRet = 0;
        SwRectFnSet aRectFnSet(pStart);
        while ( pStart && nCount > 0 )
        {
            nRet += aRectFnSet.GetHeight(pStart->getFrameArea());
            pStart = pStart->GetNext();
            --nCount;
        }

        return nRet;
    }

    // Local helper function to insert a new follow flow line
    static SwRowFrame* lcl_InsertNewFollowFlowLine( SwTabFrame& rTab, const SwFrame& rTmpRow, bool bRowSpanLine )
    {
        OSL_ENSURE( rTmpRow.IsRowFrame(), "No row frame to copy for FollowFlowLine" );
        const SwRowFrame& rRow = static_cast<const SwRowFrame&>(rTmpRow);

        rTab.SetFollowFlowLine( true );
        SwRowFrame *pFollowFlowLine = new SwRowFrame(*rRow.GetTabLine(), &rTab, false );
        pFollowFlowLine->SetRowSpanLine( bRowSpanLine );
        SwFrame* pFirstRow = rTab.GetFollow()->GetFirstNonHeadlineRow();
        pFollowFlowLine->InsertBefore( rTab.GetFollow(), pFirstRow );
        return pFollowFlowLine;
    }

    // #i26945# - local helper function to invalidate all lower
    // objects. By parameter <_bMoveObjsOutOfRange> it can be controlled, if
    // additionally the objects are moved 'out of range'.
    static void lcl_InvalidateLowerObjs( SwLayoutFrame& _rLayoutFrame,
                                  const bool _bMoveObjsOutOfRange = false,
                                  SwPageFrame* _pPageFrame = nullptr )
    {
        // determine page frame, if needed
        if ( !_pPageFrame )
        {
            _pPageFrame = _rLayoutFrame.FindPageFrame();
            OSL_ENSURE( _pPageFrame,
                    "<lcl_InvalidateLowerObjs(..)> - missing page frame -> no move of lower objects out of range" );
            if ( !_pPageFrame )
            {
                return;
            }
        }

        // loop on lower frames
        SwFrame* pLowerFrame = _rLayoutFrame.Lower();
        while ( pLowerFrame )
        {
            if ( pLowerFrame->IsLayoutFrame() )
            {
                ::lcl_InvalidateLowerObjs( *static_cast<SwLayoutFrame*>(pLowerFrame),
                                           _bMoveObjsOutOfRange, _pPageFrame );
            }
            if ( pLowerFrame->GetDrawObjs() )
            {
                for (SwAnchoredObject* pAnchoredObj : *pLowerFrame->GetDrawObjs())
                {
                    // invalidate position of anchored object
                    pAnchoredObj->SetTmpConsiderWrapInfluence( false );
                    pAnchoredObj->SetConsiderForTextWrap( false );
                    pAnchoredObj->UnlockPosition();
                    pAnchoredObj->InvalidateObjPos();

                    SwFlyFrame *pFly = dynamic_cast<SwFlyFrame*>(pAnchoredObj);

                    // move anchored object 'out of range'
                    if ( _bMoveObjsOutOfRange )
                    {
                        // indicate, that positioning is progress to avoid
                        // modification of the anchored object resp. it's attributes
                        // due to the movement
                        SwObjPositioningInProgress aObjPosInProgress( *pAnchoredObj );
                        pAnchoredObj->SetObjLeft( _pPageFrame->getFrameArea().Right() );
                        // #115759# - reset character rectangle,
                        // top of line and relative position in order to assure,
                        // that anchored object is correctly positioned.
                        pAnchoredObj->ClearCharRectAndTopOfLine();
                        pAnchoredObj->SetCurrRelPos( Point( 0, 0 ) );
                        if ( pAnchoredObj->GetFrameFormat().GetAnchor().GetAnchorId()
                                == RndStdIds::FLY_AS_CHAR )
                        {
                            pAnchoredObj->AnchorFrame()
                                    ->Prepare( PREP_FLY_ATTR_CHG,
                                               &(pAnchoredObj->GetFrameFormat()) );
                        }
                        if ( pFly != nullptr )
                        {
                            pFly->GetVirtDrawObj()->SetRectsDirty();
                            pFly->GetVirtDrawObj()->SetChanged();
                        }
                    }

                    // If anchored object is a fly frame, invalidate its lower objects
                    if ( pFly != nullptr )
                    {
                        ::lcl_InvalidateLowerObjs( *pFly, _bMoveObjsOutOfRange, _pPageFrame );
                    }
                }
            }
            pLowerFrame = pLowerFrame->GetNext();
        }
    }

    // Local helper function to shrink all lowers of pRow to 0 height
    static void lcl_ShrinkCellsAndAllContent( SwRowFrame& rRow )
    {
        SwCellFrame* pCurrMasterCell = static_cast<SwCellFrame*>(rRow.Lower());
        SwRectFnSet aRectFnSet(pCurrMasterCell);

        bool bAllCellsCollapsed = true;
        while ( pCurrMasterCell )
        {
            // NEW TABLES
            SwCellFrame& rToAdjust = pCurrMasterCell->GetTabBox()->getRowSpan() < 1 ?
                                   const_cast<SwCellFrame&>(pCurrMasterCell->FindStartEndOfRowSpanCell( true )) :
                                   *pCurrMasterCell;

            // #i26945#
            // all lowers should have the correct position
            lcl_ArrangeLowers( &rToAdjust,
                               aRectFnSet.GetPrtTop(rToAdjust),
                               false );
            // TODO: Optimize number of frames which are set to 0 height
            // we have to start with the last lower frame, otherwise
            // the shrink will not shrink the current cell
            SwFrame* pTmp = rToAdjust.GetLastLower();
            bool bAllLowersCollapsed = true;

            if ( pTmp && pTmp->IsRowFrame() )
            {
                SwRowFrame* pTmpRow = static_cast<SwRowFrame*>(pTmp);
                lcl_ShrinkCellsAndAllContent( *pTmpRow );
            }
            else
            {
                // TODO: Optimize number of frames which are set to 0 height
                while ( pTmp )
                {
                    // the frames have to be shrunk
                    if ( pTmp->IsTabFrame() )
                    {
                        SwRowFrame* pTmpRow = static_cast<SwRowFrame*>(static_cast<SwTabFrame*>(pTmp)->Lower());
                        bool bAllRowsCollapsed = true;

                        while ( pTmpRow )
                        {
                            lcl_ShrinkCellsAndAllContent( *pTmpRow );

                            if (aRectFnSet.GetHeight(pTmpRow->getFrameArea()) > 0)
                                bAllRowsCollapsed = false;

                            pTmpRow = static_cast<SwRowFrame*>(pTmpRow->GetNext());
                        }

                        if (bAllRowsCollapsed)
                        {
                            // All rows of this table have 0 height -> set height of the table itself as well.
                            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pTmp);
                            aRectFnSet.SetHeight(aFrm, 0);

                            SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pTmp);
                            aRectFnSet.SetTop(aPrt, 0);
                            aRectFnSet.SetHeight(aPrt, 0);
                        }
                        else
                            bAllLowersCollapsed = false;
                    }
                    else
                    {
                        pTmp->Shrink(aRectFnSet.GetHeight(pTmp->getFrameArea()));
                        SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pTmp);
                        aRectFnSet.SetTop(aPrt, 0);
                        aRectFnSet.SetHeight(aPrt, 0);

                        if (aRectFnSet.GetHeight(pTmp->getFrameArea()) > 0)
                        {
                            bAllLowersCollapsed = false;
                        }
                    }

                    pTmp = pTmp->GetPrev();
                }

                // all lowers should have the correct position
                lcl_ArrangeLowers( &rToAdjust,
                                   aRectFnSet.GetPrtTop(rToAdjust),
                                   false );
            }

            if (bAllLowersCollapsed)
            {
                // All lower frame of this cell have 0 height -> set height of the cell itself as well.
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pCurrMasterCell);
                aRectFnSet.SetHeight(aFrm, 0);

                SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pCurrMasterCell);
                aRectFnSet.SetTop(aPrt, 0);
                aRectFnSet.SetHeight(aPrt, 0);
            }
            else
                bAllCellsCollapsed = false;

            pCurrMasterCell = static_cast<SwCellFrame*>(pCurrMasterCell->GetNext());
        }

        if (bAllCellsCollapsed)
        {
            // All cells have 0 height -> set height of row as well.
            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(rRow);
            aRectFnSet.SetHeight(aFrm, 0);

            SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(rRow);
            aRectFnSet.SetTop(aPrt, 0);
            aRectFnSet.SetHeight(aPrt, 0);
        }
    }

    // Local helper function to move the content from rSourceLine to rDestLine
    // The content is inserted behind the last content in the corresponding
    // cell in rDestLine.
    static void lcl_MoveRowContent( SwRowFrame& rSourceLine, SwRowFrame& rDestLine )
    {
        SwCellFrame* pCurrDestCell = static_cast<SwCellFrame*>(rDestLine.Lower());
        SwCellFrame* pCurrSourceCell = static_cast<SwCellFrame*>(rSourceLine.Lower());

        // Move content of follow cells into master cells
        while ( pCurrSourceCell )
        {
            if ( pCurrSourceCell->Lower() && pCurrSourceCell->Lower()->IsRowFrame() )
            {
                SwRowFrame* pTmpSourceRow = static_cast<SwRowFrame*>(pCurrSourceCell->Lower());
                while ( pTmpSourceRow )
                {
                    // #125926# Attention! It is possible,
                    // that pTmpSourceRow->IsFollowFlowRow() but pTmpDestRow
                    // cannot be found. In this case, we have to move the complete
                    // row.
                    SwRowFrame* pTmpDestRow = static_cast<SwRowFrame*>(pCurrDestCell->Lower());

                    if ( pTmpSourceRow->IsFollowFlowRow() && pTmpDestRow )
                    {
                        // move content from follow flow row to pTmpDestRow:
                        while ( pTmpDestRow->GetNext() )
                            pTmpDestRow = static_cast<SwRowFrame*>(pTmpDestRow->GetNext());

                        OSL_ENSURE( pTmpDestRow->GetFollowRow() == pTmpSourceRow, "Table contains node" );

                        lcl_MoveRowContent( *pTmpSourceRow, *pTmpDestRow );
                        pTmpDestRow->SetFollowRow( pTmpSourceRow->GetFollowRow() );
                        pTmpSourceRow->RemoveFromLayout();
                        SwFrame::DestroyFrame(pTmpSourceRow);
                    }
                    else
                    {
                        // move complete row:
                        pTmpSourceRow->RemoveFromLayout();
                        pTmpSourceRow->InsertBefore( pCurrDestCell, nullptr );
                    }

                    pTmpSourceRow = static_cast<SwRowFrame*>(pCurrSourceCell->Lower());
                }
            }
            else
            {
                SwFrame *pTmp = ::SaveContent( pCurrSourceCell );
                if ( pTmp )
                {
                    // NEW TABLES
                    SwCellFrame* pDestCell = pCurrDestCell;
                    if ( pDestCell->GetTabBox()->getRowSpan() < 1 )
                        pDestCell = & const_cast<SwCellFrame&>(pDestCell->FindStartEndOfRowSpanCell( true ));

                    // Find last content
                    SwFrame* pFrame = pDestCell->GetLastLower();
                    ::RestoreContent( pTmp, pDestCell, pFrame );
                }
            }
            pCurrDestCell = static_cast<SwCellFrame*>(pCurrDestCell->GetNext());
            pCurrSourceCell = static_cast<SwCellFrame*>(pCurrSourceCell->GetNext());
        }
    }

    // Local helper function to move all footnotes in rRowFrame from
    // the footnote boss of rSource to the footnote boss of rDest.
    static void lcl_MoveFootnotes( SwTabFrame& rSource, SwTabFrame& rDest, SwLayoutFrame& rRowFrame )
    {
        if ( !rSource.GetFormat()->GetDoc()->GetFootnoteIdxs().empty() )
        {
            SwFootnoteBossFrame* pOldBoss = rSource.FindFootnoteBossFrame( true );
            SwFootnoteBossFrame* pNewBoss = rDest.FindFootnoteBossFrame( true );
            rRowFrame.MoveLowerFootnotes( nullptr, pOldBoss, pNewBoss, true );
        }
    }

    // Local helper function to handle nested table cells before the split process
    static void lcl_PreprocessRowsInCells( SwTabFrame& rTab, SwRowFrame& rLastLine,
                                    SwRowFrame& rFollowFlowLine, SwTwips nRemain )
    {
        SwCellFrame* pCurrLastLineCell = static_cast<SwCellFrame*>(rLastLine.Lower());
        SwCellFrame* pCurrFollowFlowLineCell = static_cast<SwCellFrame*>(rFollowFlowLine.Lower());

        SwRectFnSet aRectFnSet(pCurrLastLineCell);

        // Move content of follow cells into master cells
        while ( pCurrLastLineCell )
        {
            if ( pCurrLastLineCell->Lower() && pCurrLastLineCell->Lower()->IsRowFrame() )
            {
                SwTwips nTmpCut = nRemain;
                SwRowFrame* pTmpLastLineRow = static_cast<SwRowFrame*>(pCurrLastLineCell->Lower());

                // #i26945#
                SwTwips nCurrentHeight =
                        lcl_CalcMinRowHeight( pTmpLastLineRow,
                                              rTab.IsConsiderObjsForMinCellHeight() );
                while ( pTmpLastLineRow->GetNext() && nTmpCut > nCurrentHeight )
                {
                    nTmpCut -= nCurrentHeight;
                    pTmpLastLineRow = static_cast<SwRowFrame*>(pTmpLastLineRow->GetNext());
                    // #i26945#
                    nCurrentHeight =
                        lcl_CalcMinRowHeight( pTmpLastLineRow,
                                              rTab.IsConsiderObjsForMinCellHeight() );
                }

                // pTmpLastLineRow does not fit to the line or it is the last line
                // Check if we can move pTmpLastLineRow to the follow table,
                // or if we have to split the line:
                bool bTableLayoutTooComplex = false;
                long nMinHeight = 0;

                // We have to take into account:
                // 1. The fixed height of the row
                // 2. The borders of the cells inside the row
                // 3. The minimum height of the row
                if ( pTmpLastLineRow->HasFixSize() )
                    nMinHeight = aRectFnSet.GetHeight(pTmpLastLineRow->getFrameArea());
                else
                {
                    {
                        const SwFormatFrameSize &rSz = pTmpLastLineRow->GetFormat()->GetFrameSize();
                        if ( rSz.GetHeightSizeType() == ATT_MIN_SIZE )
                            nMinHeight = rSz.GetHeight() - lcl_calcHeightOfRowBeforeThisFrame(*pTmpLastLineRow);
                    }

                    SwFrame* pCell = pTmpLastLineRow->Lower();
                    while ( pCell )
                    {
                        if ( static_cast<SwCellFrame*>(pCell)->Lower() &&
                             static_cast<SwCellFrame*>(pCell)->Lower()->IsRowFrame() )
                        {
                            bTableLayoutTooComplex = true;
                            break;
                        }

                        SwBorderAttrAccess aAccess( SwFrame::GetCache(), pCell );
                        const SwBorderAttrs &rAttrs = *aAccess.Get();
                        nMinHeight = std::max( nMinHeight, lcl_CalcTopAndBottomMargin( *static_cast<SwLayoutFrame*>(pCell), rAttrs ) );
                        pCell = pCell->GetNext();
                    }
                }

                // 1. Case:
                // The line completely fits into the master table.
                // Nevertheless, we build a follow (otherwise painting problems
                // with empty cell).

                // 2. Case:
                // The line has to be split, the minimum height still fits into
                // the master table, and the table structure is not too complex.
                if ( nTmpCut > nCurrentHeight ||
                     ( pTmpLastLineRow->IsRowSplitAllowed() &&
                      !bTableLayoutTooComplex && nMinHeight < nTmpCut ) )
                {
                    // The line has to be split:
                    SwRowFrame* pNewRow = new SwRowFrame( *pTmpLastLineRow->GetTabLine(), &rTab, false );
                    pNewRow->SetFollowFlowRow( true );
                    pNewRow->SetFollowRow( pTmpLastLineRow->GetFollowRow() );
                    pTmpLastLineRow->SetFollowRow( pNewRow );
                    pNewRow->InsertBehind( pCurrFollowFlowLineCell, nullptr );
                    pTmpLastLineRow = static_cast<SwRowFrame*>(pTmpLastLineRow->GetNext());
                }

                // The following lines have to be moved:
                while ( pTmpLastLineRow )
                {
                    SwRowFrame* pTmp = static_cast<SwRowFrame*>(pTmpLastLineRow->GetNext());
                    lcl_MoveFootnotes( rTab, *rTab.GetFollow(), *pTmpLastLineRow );
                    pTmpLastLineRow->RemoveFromLayout();
                    pTmpLastLineRow->InsertBefore( pCurrFollowFlowLineCell, nullptr );
                    pTmpLastLineRow->Shrink( aRectFnSet.GetHeight(pTmpLastLineRow->getFrameArea()) );
                    pCurrFollowFlowLineCell->Grow( aRectFnSet.GetHeight(pTmpLastLineRow->getFrameArea()) );
                    pTmpLastLineRow = pTmp;
                }
            }

            pCurrLastLineCell = static_cast<SwCellFrame*>(pCurrLastLineCell->GetNext());
            pCurrFollowFlowLineCell = static_cast<SwCellFrame*>(pCurrFollowFlowLineCell->GetNext());
        }
    }

    // Local helper function to handle nested table cells after the split process
    static void lcl_PostprocessRowsInCells( SwTabFrame& rTab, SwRowFrame& rLastLine )
    {
        SwCellFrame* pCurrMasterCell = static_cast<SwCellFrame*>(rLastLine.Lower());
        while ( pCurrMasterCell )
        {
            if ( pCurrMasterCell->Lower() &&
                 pCurrMasterCell->Lower()->IsRowFrame() )
            {
                SwRowFrame* pRowFrame = static_cast<SwRowFrame*>(pCurrMasterCell->GetLastLower());

                if ( nullptr != pRowFrame->GetPrev() && !pRowFrame->ContainsContent() )
                {
                    OSL_ENSURE( pRowFrame->GetFollowRow(), "Deleting row frame without follow" );

                    // The footnotes have to be moved:
                    lcl_MoveFootnotes( rTab, *rTab.GetFollow(), *pRowFrame );
                    pRowFrame->Cut();
                    SwRowFrame* pFollowRow = pRowFrame->GetFollowRow();
                    pRowFrame->Paste( pFollowRow->GetUpper(), pFollowRow );
                    pRowFrame->SetFollowRow( pFollowRow->GetFollowRow() );
                    lcl_MoveRowContent( *pFollowRow, *pRowFrame );
                    pFollowRow->Cut();
                    SwFrame::DestroyFrame(pFollowRow);
                    ::SwInvalidateAll( pCurrMasterCell, LONG_MAX );
                }
            }

            pCurrMasterCell = static_cast<SwCellFrame*>(pCurrMasterCell->GetNext());
        }
    }

    // Local helper function to re-calculate the split line.
    inline void TableSplitRecalcLock( SwFlowFrame *pTab ) { pTab->LockJoin(); }
    inline void TableSplitRecalcUnlock( SwFlowFrame *pTab ) { pTab->UnlockJoin(); }

    static bool lcl_RecalcSplitLine( SwRowFrame& rLastLine, SwRowFrame& rFollowLine,
                              SwTwips nRemainingSpaceForLastRow, SwTwips nAlreadyFree )
    {
        bool bRet = true;

        vcl::RenderContext* pRenderContext = rLastLine.getRootFrame()->GetCurrShell()->GetOut();
        SwTabFrame& rTab = static_cast<SwTabFrame&>(*rLastLine.GetUpper());
        SwRectFnSet aRectFnSet(rTab.GetUpper());
        SwTwips nCurLastLineHeight = aRectFnSet.GetHeight(rLastLine.getFrameArea());

        // If there are nested cells in rLastLine, the recalculation of the last
        // line needs some preprocessing.
        lcl_PreprocessRowsInCells( rTab, rLastLine, rFollowLine, nRemainingSpaceForLastRow );

        // Here the recalculation process starts:
        rTab.SetRebuildLastLine( true );
        // #i26945#
        rTab.SetDoesObjsFit( true );

        // #i26945# - invalidate and move floating screen
        // objects 'out of range'
        ::lcl_InvalidateLowerObjs( rLastLine, true );

        // manipulate row and cell sizes

        // #i26945# - Do *not* consider floating screen objects
        // for the minimal cell height.
        rTab.SetConsiderObjsForMinCellHeight( false );
        ::lcl_ShrinkCellsAndAllContent( rLastLine );
        rTab.SetConsiderObjsForMinCellHeight( true );

        // invalidate last line
        ::SwInvalidateAll( &rLastLine, LONG_MAX );

        // Shrink the table to account for the shrunk last row, as well as lower rows
        // that had been moved to follow table in SwTabFrame::Split.
        // It will grow later when last line will recalc its height.
        rTab.Shrink(nAlreadyFree + nCurLastLineHeight - nRemainingSpaceForLastRow + 1);

        // Lock this tab frame and its follow
        bool bUnlockMaster = false;
        SwFlowFrame * pFollow = nullptr;
        SwTabFrame* pMaster = rTab.IsFollow() ? rTab.FindMaster() : nullptr;
        if ( pMaster && !pMaster->IsJoinLocked() )
        {
            bUnlockMaster = true;
            ::TableSplitRecalcLock( pMaster );
        }
        if ( !rTab.GetFollow()->IsJoinLocked() )
        {
            pFollow = rTab.GetFollow();
            ::TableSplitRecalcLock( pFollow );
        }

        bool bInSplit = rLastLine.IsInSplit();
        rLastLine.SetInSplit();

        // Do the recalculation
        lcl_RecalcRow( &rLastLine, LONG_MAX );
        // #115759# - force a format of the last line in order to
        // get the correct height.
        rLastLine.InvalidateSize();
        rLastLine.Calc(pRenderContext);

        rLastLine.SetInSplit(bInSplit);

        // Unlock this tab frame and its follow
        if ( pFollow )
            ::TableSplitRecalcUnlock( pFollow );
        if ( bUnlockMaster )
            ::TableSplitRecalcUnlock( pMaster );

        // If there are nested cells in rLastLine, the recalculation of the last
        // line needs some postprocessing.
        lcl_PostprocessRowsInCells( rTab, rLastLine );

        // Do a couple of checks on the current situation.

        // If we are not happy with the current situation we return false.
        // This will start a new try to split the table, this time we do not
        // try to split the table rows.

        // 1. Check if table fits to its upper.
        // #i26945# - include check, if objects fit
        const SwTwips nDistanceToUpperPrtBottom =
            aRectFnSet.BottomDist(rTab.getFrameArea(), aRectFnSet.GetPrtBottom(*rTab.GetUpper()));
        if ( nDistanceToUpperPrtBottom < 0 || !rTab.DoesObjsFit() )
            bRet = false;

        // 2. Check if each cell in the last line has at least one content frame.

        // Note: a FollowFlowRow may contains empty cells!
        if ( bRet )
        {
            if ( !rLastLine.IsInFollowFlowRow() )
            {
                SwCellFrame* pCurrMasterCell = static_cast<SwCellFrame*>(rLastLine.Lower());
                while ( pCurrMasterCell )
                {
                    if ( !pCurrMasterCell->ContainsContent() && pCurrMasterCell->GetTabBox()->getRowSpan() >= 1 )
                    {
                        bRet = false;
                        break;
                    }
                    pCurrMasterCell = static_cast<SwCellFrame*>(pCurrMasterCell->GetNext());
                }
            }
        }

        // 3. Check if last line does not contain any content:
        if ( bRet )
        {
            if ( !rLastLine.ContainsContent() )
            {
                bRet = false;
            }
        }

        // 4. Check if follow flow line does not contain content:
        if ( bRet )
        {
            if ( !rFollowLine.IsRowSpanLine() && !rFollowLine.ContainsContent() )
            {
                bRet = false;
            }
        }

        if ( bRet )
        {
            // Everything looks fine. Splitting seems to be successful. We invalidate
            // rFollowLine to force a new formatting.
            ::SwInvalidateAll( &rFollowLine, LONG_MAX );
        }
        else
        {
            // Splitting the table row gave us an unexpected result.
            // Everything has to be prepared for a second try to split
            // the table, this time without splitting the row.
            ::SwInvalidateAll( &rLastLine, LONG_MAX );
        }

        rTab.SetRebuildLastLine( false );
        // #i26945#
        rTab.SetDoesObjsFit( true );

        return bRet;
    }

    // Sets the correct height for all spanned cells
    static void lcl_AdjustRowSpanCells( SwRowFrame* pRow )
    {
        SwRectFnSet aRectFnSet(pRow);
        SwCellFrame* pCellFrame = static_cast<SwCellFrame*>(pRow->GetLower());
        while ( pCellFrame )
        {
            const long nLayoutRowSpan = pCellFrame->GetLayoutRowSpan();
            if ( nLayoutRowSpan > 1 )
            {
                // calculate height of cell:
                const long nNewCellHeight = lcl_GetHeightOfRows( pRow, nLayoutRowSpan );
                const long nDiff = nNewCellHeight - aRectFnSet.GetHeight(pCellFrame->getFrameArea());

                if ( nDiff )
                {
                    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pCellFrame);
                    aRectFnSet.AddBottom(aFrm, nDiff);
                }
            }

            pCellFrame = static_cast<SwCellFrame*>(pCellFrame->GetNext());
        }
    }

    // Returns the maximum layout row span of the row
    // Looking for the next row that contains no covered cells:
    static long lcl_GetMaximumLayoutRowSpan( const SwRowFrame& rRow )
    {
        long nRet = 1;

        const SwRowFrame* pCurrentRowFrame = static_cast<const SwRowFrame*>(rRow.GetNext());
        bool bNextRow = false;

        while ( pCurrentRowFrame )
        {
            // if there is any covered cell, we proceed to the next row frame
            const SwCellFrame* pLower = static_cast<const SwCellFrame*>( pCurrentRowFrame->Lower());
            while ( pLower )
            {
                if ( pLower->GetTabBox()->getRowSpan() < 0 )
                {
                    ++nRet;
                    bNextRow = true;
                    break;
                }
                pLower = static_cast<const SwCellFrame*>(pLower->GetNext());
            }
            pCurrentRowFrame = bNextRow ?
                             static_cast<const SwRowFrame*>(pCurrentRowFrame->GetNext() ) :
                             nullptr;
        }

        return nRet;
    }

    // Function to remove the FollowFlowLine of rTab.
    // The content of the FollowFlowLine is moved to the associated line in the
    // master table.
    bool SwTabFrame::RemoveFollowFlowLine()
    {
        // find FollowFlowLine
        SwTabFrame *pFoll = GetFollow();
        SwRowFrame* pFollowFlowLine = pFoll ? pFoll->GetFirstNonHeadlineRow() : nullptr;

        // find last row in master
        SwFrame* pLastLine = GetLastLower();

        OSL_ENSURE( HasFollowFlowLine() &&
                pFollowFlowLine &&
                pLastLine, "There should be a flowline in the follow" );

        // We have to reset the flag here, because lcl_MoveRowContent
        // calls a GrowFrame(), which has a different behavior if
        // this flag is set.
        SetFollowFlowLine( false );

        // #140081# Make code robust.
        if ( !pFollowFlowLine || !pLastLine )
            return true;

        // Move content
        lcl_MoveRowContent( *pFollowFlowLine, *static_cast<SwRowFrame*>(pLastLine) );

        // NEW TABLES
        // If a row span follow flow line is removed, we want to move the whole span
        // to the master:
        long nRowsToMove = lcl_GetMaximumLayoutRowSpan( *pFollowFlowLine );

        if ( nRowsToMove > 1 )
        {
            SwRectFnSet aRectFnSet(this);
            SwFrame* pRow = pFollowFlowLine->GetNext();
            SwFrame* pInsertBehind = GetLastLower();
            SwTwips nGrow = 0;

            while ( pRow && nRowsToMove-- > 1 )
            {
                SwFrame* pNxt = pRow->GetNext();
                nGrow += aRectFnSet.GetHeight(pRow->getFrameArea());

                // The footnotes have to be moved:
                lcl_MoveFootnotes( *GetFollow(), *this, static_cast<SwRowFrame&>(*pRow) );

                pRow->RemoveFromLayout();
                pRow->InsertBehind( this, pInsertBehind );
                pRow->InvalidateAll_();
                pRow->CheckDirChange();
                pInsertBehind = pRow;
                pRow = pNxt;
            }

            SwFrame* pFirstRow = Lower();
            while ( pFirstRow )
            {
                lcl_AdjustRowSpanCells( static_cast<SwRowFrame*>(pFirstRow) );
                pFirstRow = pFirstRow->GetNext();
            }

            Grow( nGrow );
            GetFollow()->Shrink( nGrow );
        }

        bool bJoin = !pFollowFlowLine->GetNext();
        pFollowFlowLine->Cut();
        SwFrame::DestroyFrame(pFollowFlowLine);

        return bJoin;
    }

    // #i26945# - Floating screen objects are no longer searched.
    static bool lcl_FindSectionsInRow( const SwRowFrame& rRow )
    {
        bool bRet = false;
        const SwCellFrame* pLower = static_cast<const SwCellFrame*>(rRow.Lower());
        while ( pLower )
        {
            if ( pLower->IsVertical() != rRow.IsVertical() )
                return true;

            const SwFrame* pTmpFrame = pLower->Lower();
            while ( pTmpFrame )
            {
                if ( pTmpFrame->IsRowFrame() )
                {
                    bRet = lcl_FindSectionsInRow( *static_cast<const SwRowFrame*>(pTmpFrame) );
                }
                else
                {
                    // #i26945# - search only for sections
                    if (pTmpFrame->IsSctFrame())
                    {
                        bRet = true;

                        if (!rRow.IsInSct())
                        {
                            // This row is not in a section.
                            if (const SwFrame* pSectionLower = pTmpFrame->GetLower())
                            {
                                if (!pSectionLower->IsColumnFrame())
                                {
                                    // Section has a single column only, try to
                                    // split that.
                                    bRet = false;

                                    for (const SwFrame* pFrame = pSectionLower; pFrame; pFrame = pFrame->GetNext())
                                    {
                                        if (pFrame->IsTabFrame())
                                        {
                                            // Section contains a table, no split in that case.
                                            bRet = true;
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                if ( bRet )
                    return true;
                pTmpFrame = pTmpFrame->GetNext();
            }

            pLower = static_cast<const SwCellFrame*>(pLower->GetNext());
        }
        return bRet;
    }

    bool SwTabFrame::Split( const SwTwips nCutPos, bool bTryToSplit, bool bTableRowKeep )
    {
        bool bRet = true;

        SwRectFnSet aRectFnSet(this);

        // #i26745# - format row and cell frames of table
        {
            Lower()->InvalidatePos_();
            // #i43913# - correction
            // call method <lcl_InnerCalcLayout> with first lower.
            lcl_InnerCalcLayout( Lower(), LONG_MAX, true );
        }

        //In order to be able to compare the positions of the cells with CutPos,
        //they have to be calculated consecutively starting from the table.
        //They can definitely be invalid because of position changes of the table.
        SwRowFrame *pRow = static_cast<SwRowFrame*>(Lower());
        if( !pRow )
            return bRet;

        const sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat();
        sal_uInt16 nRowCount = 0;           // pRow currently points to the first row

        SwTwips nRemainingSpaceForLastRow =
            aRectFnSet.YDiff(nCutPos, aRectFnSet.GetTop(getFrameArea()));
        nRemainingSpaceForLastRow -= aRectFnSet.GetTopMargin(*this);

        // Make pRow point to the line that does not fit anymore:
        while( pRow->GetNext() &&
               nRemainingSpaceForLastRow >= ( aRectFnSet.GetHeight(pRow->getFrameArea()) +
                                               (IsCollapsingBorders() ?
                                                pRow->GetBottomLineSize() :
                                                0 ) ) )
        {
            if( bTryToSplit || !pRow->IsRowSpanLine() ||
                0 != aRectFnSet.GetHeight(pRow->getFrameArea()) )
                ++nRowCount;
            nRemainingSpaceForLastRow -= aRectFnSet.GetHeight(pRow->getFrameArea());
            pRow = static_cast<SwRowFrame*>(pRow->GetNext());
        }

        // bSplitRowAllowed: Row may be split according to its attributes.
        // bTryToSplit:      Row will never be split if bTryToSplit = false.
        //                   This can either be passed as a parameter, indicating
        //                   that we are currently doing the second try to split the
        //                   table, or it will be set to false under certain
        //                   conditions that are not suitable for splitting
        //                   the row.
        bool bSplitRowAllowed = pRow->IsRowSplitAllowed();

        // #i29438#
        // #i26945# - Floating screen objects no longer forbid
        // a splitting of the table row.
        // Special DoNotSplit case 1:
        // Search for sections inside pRow:
        if ( lcl_FindSectionsInRow( *pRow ) )
        {
            bTryToSplit = false;
        }

        // #i29771#
        // To avoid loops, we do some checks before actually trying to split
        // the row. Maybe we should keep the next row in this table.
        // Note: This is only done if we are at the beginning of our upper
        bool bKeepNextRow = false;
        if ( nRowCount < nRepeat )
        {
            // First case: One of the repeated headline does not fit to the page anymore.
            // At least one more non-heading row has to stay in this table in
            // order to avoid loops:
            OSL_ENSURE( !GetIndPrev(), "Table is supposed to be at beginning" );
            bKeepNextRow = true;
        }
        else if ( !GetIndPrev() && nRepeat == nRowCount )
        {
            // Second case: The first non-headline row does not fit to the page.
            // If it is not allowed to be split, or it contains a sub-row that
            // is not allowed to be split, we keep the row in this table:
            if ( bTryToSplit && bSplitRowAllowed )
            {
                // Check if there are (first) rows inside this row,
                // which are not allowed to be split.
                SwCellFrame* pLowerCell = static_cast<SwCellFrame*>(pRow->Lower());
                while ( pLowerCell )
                {
                    if ( pLowerCell->Lower() && pLowerCell->Lower()->IsRowFrame() )
                    {
                        const SwRowFrame* pLowerRow = static_cast<SwRowFrame*>(pLowerCell->Lower());
                        if ( !pLowerRow->IsRowSplitAllowed() &&
                            aRectFnSet.GetHeight(pLowerRow->getFrameArea()) > nRemainingSpaceForLastRow )
                        {
                            bKeepNextRow = true;
                            break;
                        }
                    }
                    pLowerCell = static_cast<SwCellFrame*>(pLowerCell->GetNext());
                }
            }
            else
                bKeepNextRow = true;
        }

        // Better keep the next row in this table:
        if ( bKeepNextRow )
        {
            pRow = GetFirstNonHeadlineRow();
            if ( pRow && pRow->IsRowSpanLine() && 0 == aRectFnSet.GetHeight(pRow->getFrameArea()) )
                pRow = static_cast<SwRowFrame*>(pRow->GetNext());
            if ( pRow )
            {
                pRow = static_cast<SwRowFrame*>(pRow->GetNext());
                ++nRowCount;
            }
        }

        // No more row to split or to move to follow table:
        if ( !pRow )
            return bRet;

        // We try to split the row if
        // - the attributes of the row are set accordingly and
        // - we are allowed to do so
        // - it should not be kept with the next row
        bSplitRowAllowed = bSplitRowAllowed && bTryToSplit &&
                           ( !bTableRowKeep ||
                             !pRow->ShouldRowKeepWithNext() );

        // Adjust pRow according to the keep-with-next attribute:
        if ( !bSplitRowAllowed && bTableRowKeep )
        {
            SwRowFrame* pTmpRow = static_cast<SwRowFrame*>(pRow->GetPrev());
            SwRowFrame* pOldRow = pRow;
            while ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() &&
                    nRowCount > nRepeat )
            {
                pRow = pTmpRow;
                --nRowCount;
                pTmpRow = static_cast<SwRowFrame*>(pTmpRow->GetPrev());
            }

            // loop prevention
            if ( nRowCount == nRepeat && !GetIndPrev())
            {
                pRow = pOldRow;
            }
        }

        // If we do not intend to split pRow, we check if we are
        // allowed to move pRow to a follow. Otherwise we return
        // false, indicating an error
        if ( !bSplitRowAllowed )
        {
            SwRowFrame* pFirstNonHeadlineRow = GetFirstNonHeadlineRow();
            if ( pRow == pFirstNonHeadlineRow )
                return false;

            // #i91764#
            // Ignore row span lines
            SwRowFrame* pTmpRow = pFirstNonHeadlineRow;
            while ( pTmpRow && pTmpRow->IsRowSpanLine() )
            {
                pTmpRow = static_cast<SwRowFrame*>(pTmpRow->GetNext());
            }
            if ( !pTmpRow || pRow == pTmpRow )
            {
                return false;
            }
        }

        // Build follow table if not already done:
        bool bNewFollow;
        SwTabFrame *pFoll;
        if ( GetFollow() )
        {
            pFoll = GetFollow();
            bNewFollow = false;
        }
        else
        {
            bNewFollow = true;
            pFoll = new SwTabFrame( *this );

            // We give the follow table an initial width.
            {
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFoll);
                aRectFnSet.AddWidth(aFrm, aRectFnSet.GetWidth(getFrameArea()));
                aRectFnSet.SetLeft(aFrm, aRectFnSet.GetLeft(getFrameArea()));
            }

            {
                SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pFoll);
                aRectFnSet.AddWidth(aPrt, aRectFnSet.GetWidth(getFramePrintArea()));
            }

            // Insert the new follow table
            pFoll->InsertBehind( GetUpper(), this );

            // Repeat the headlines.
            for ( nRowCount = 0; nRowCount < nRepeat; ++nRowCount )
            {
                // Insert new headlines:
                bDontCreateObjects = true;              //frmtool
                SwRowFrame* pHeadline = new SwRowFrame(
                                        *GetTable()->GetTabLines()[ nRowCount ], this );
                pHeadline->SetRepeatedHeadline( true );
                bDontCreateObjects = false;
                pHeadline->InsertBefore( pFoll, nullptr );

                SwPageFrame *pPage = pHeadline->FindPageFrame();
                const SwFrameFormats *pTable = GetFormat()->GetDoc()->GetSpzFrameFormats();
                if( !pTable->empty() )
                {
                    sal_uLong nIndex;
                    SwContentFrame* pFrame = pHeadline->ContainsContent();
                    while( pFrame )
                    {
                        // sw_redlinehide: the implementation of AppendObjs
                        // takes care of iterating merged SwTextFrame
                        nIndex = pFrame->IsTextFrame()
                            ? static_cast<SwTextFrame*>(pFrame)->GetTextNodeFirst()->GetIndex()
                            : static_cast<SwNoTextFrame*>(pFrame)->GetNode()->GetIndex();
                        AppendObjs( pTable, nIndex, pFrame, pPage, GetFormat()->GetDoc());
                        pFrame = pFrame->GetNextContentFrame();
                        if( !pHeadline->IsAnLower( pFrame ) )
                            break;
                    }
                }
            }
        }

        SwRowFrame* pLastRow = nullptr;     // points to the last remaining line in master
        SwRowFrame* pFollowRow = nullptr;   // points to either the follow flow line or the
                                            // first regular line in the follow

        if ( bSplitRowAllowed )
        {
            // If the row that does not fit anymore is allowed
            // to be split, the next row has to be moved to the follow table.
            pLastRow = pRow;
            pRow = static_cast<SwRowFrame*>(pRow->GetNext());

            // new follow flow line for last row of master table
            pFollowRow = lcl_InsertNewFollowFlowLine( *this, *pLastRow, false );
        }
        else
        {
            pFollowRow = pRow;

            // NEW TABLES
            // check if we will break a row span by moving pFollowRow to the follow:
            // In this case we want to reformat the last line.
            const SwCellFrame* pCellFrame = static_cast<const SwCellFrame*>(pFollowRow->GetLower());
            while ( pCellFrame )
            {
                if ( pCellFrame->GetTabBox()->getRowSpan() < 1 )
                {
                    pLastRow = static_cast<SwRowFrame*>(pRow->GetPrev());
                    break;
                }

                pCellFrame = static_cast<const SwCellFrame*>(pCellFrame->GetNext());
            }

            // new follow flow line for last row of master table
            if ( pLastRow )
                pFollowRow = lcl_InsertNewFollowFlowLine( *this, *pLastRow, true );
        }

        SwTwips nShrink = 0;

        //Optimization: There is no paste needed for the new Follow and the
        //optimized insert can be used (big amounts of rows luckily only occurs in
        //such situations).
        if ( bNewFollow )
        {
            SwFrame* pInsertBehind = pFoll->GetLastLower();

            while ( pRow )
            {
                SwFrame* pNxt = pRow->GetNext();
                nShrink += aRectFnSet.GetHeight(pRow->getFrameArea());
                // The footnotes do not have to be moved, this is done in the
                // MoveFwd of the follow table!!!
                pRow->RemoveFromLayout();
                pRow->InsertBehind( pFoll, pInsertBehind );
                pRow->InvalidateAll_();
                pInsertBehind = pRow;
                pRow = static_cast<SwRowFrame*>(pNxt);
            }
        }
        else
        {
            SwFrame* pPasteBefore = HasFollowFlowLine() ?
                                  pFollowRow->GetNext() :
                                  pFoll->GetFirstNonHeadlineRow();

            while ( pRow )
            {
                SwFrame* pNxt = pRow->GetNext();
                nShrink += aRectFnSet.GetHeight(pRow->getFrameArea());

                // The footnotes have to be moved:
                lcl_MoveFootnotes( *this, *GetFollow(), *pRow );

                pRow->RemoveFromLayout();
                pRow->Paste( pFoll, pPasteBefore );

                pRow->CheckDirChange();
                pRow = static_cast<SwRowFrame*>(pNxt);
            }
        }

        if ( !pLastRow )
            Shrink( nShrink );
        else
        {
            // we rebuild the last line to assure that it will be fully formatted
            // we also don't shrink here, because we will be doing that in lcl_RecalcSplitLine

            // recalculate the split line
            bRet = lcl_RecalcSplitLine( *pLastRow, *pFollowRow, nRemainingSpaceForLastRow, nShrink );

            // NEW TABLES
            // check if each cell in the row span line has a good height
            if ( bRet && pFollowRow->IsRowSpanLine() )
                lcl_AdjustRowSpanCells( pFollowRow );

            // We The RowSplitLine stuff did not work. In this case we conceal the split error:
            if ( !bRet && !bSplitRowAllowed )
            {
                bRet = true;
            }
        }

        return bRet;
    }

    void SwTabFrame::Join()
    {
        OSL_ENSURE( !HasFollowFlowLine(), "Joining follow flow line" );

        SwTabFrame *pFoll = GetFollow();

        if (pFoll && !pFoll->IsJoinLocked())
        {
            SwRectFnSet aRectFnSet(this);
            pFoll->Cut();   //Cut out first to avoid unnecessary notifications.

            SwFrame *pRow = pFoll->GetFirstNonHeadlineRow(),
                  *pNxt;

            SwFrame* pPrv = GetLastLower();

            SwTwips nHeight = 0;    //Total height of the inserted rows as return value.

            while ( pRow )
            {
                pNxt = pRow->GetNext();
                nHeight += aRectFnSet.GetHeight(pRow->getFrameArea());
                pRow->RemoveFromLayout();
                pRow->InvalidateAll_();
                pRow->InsertBehind( this, pPrv );
                pRow->CheckDirChange();
                pPrv = pRow;
                pRow = pNxt;
            }

            SetFollow( pFoll->GetFollow() );
            SetFollowFlowLine( pFoll->HasFollowFlowLine() );
            SwFrame::DestroyFrame(pFoll);

            Grow( nHeight );
        }
    }

    void SwInvalidatePositions( SwFrame *pFrame, long nBottom )
    {
        // LONG_MAX == nBottom means we have to calculate all
        bool bAll = LONG_MAX == nBottom;
        SwRectFnSet aRectFnSet(pFrame);
        do
        {   pFrame->InvalidatePos_();
            pFrame->InvalidateSize_();
            if( pFrame->IsLayoutFrame() )
            {
                if ( static_cast<SwLayoutFrame*>(pFrame)->Lower() )
                {
                    ::SwInvalidatePositions( static_cast<SwLayoutFrame*>(pFrame)->Lower(), nBottom);
                    // #i26945#
                    ::lcl_InvalidateLowerObjs( *static_cast<SwLayoutFrame*>(pFrame) );
                }
            }
            else
                pFrame->Prepare( PREP_ADJUST_FRM );
            pFrame = pFrame->GetNext();
        } while ( pFrame &&
                  ( bAll ||
                  aRectFnSet.YDiff( aRectFnSet.GetTop(pFrame->getFrameArea()), nBottom ) < 0 ) );
    }

    void SwInvalidateAll( SwFrame *pFrame, long nBottom )
    {
        // LONG_MAX == nBottom means we have to calculate all
        bool bAll = LONG_MAX == nBottom;
        SwRectFnSet aRectFnSet(pFrame);
        do
        {
            pFrame->InvalidatePos_();
            pFrame->InvalidateSize_();
            pFrame->InvalidatePrt_();
            if( pFrame->IsLayoutFrame() )
            {
                // NEW TABLES
                SwLayoutFrame* pToInvalidate = static_cast<SwLayoutFrame*>(pFrame);
                SwCellFrame* pThisCell = dynamic_cast<SwCellFrame*>(pFrame);
                if ( pThisCell && pThisCell->GetTabBox()->getRowSpan() < 1 )
                {
                    pToInvalidate = & const_cast<SwCellFrame&>(pThisCell->FindStartEndOfRowSpanCell( true ));
                    pToInvalidate->InvalidatePos_();
                    pToInvalidate->InvalidateSize_();
                    pToInvalidate->InvalidatePrt_();
                }

                if ( pToInvalidate->Lower() )
                    ::SwInvalidateAll( pToInvalidate->Lower(), nBottom);
            }
            else
                pFrame->Prepare();

            pFrame = pFrame->GetNext();
        } while ( pFrame &&
                  ( bAll ||
                  aRectFnSet.YDiff( aRectFnSet.GetTop(pFrame->getFrameArea()), nBottom ) < 0 ) );
    }

    // #i29550#
    static void lcl_InvalidateAllLowersPrt( SwLayoutFrame* pLayFrame )
    {
        pLayFrame->InvalidatePrt_();
        pLayFrame->InvalidateSize_();
        pLayFrame->SetCompletePaint();

        SwFrame* pFrame = pLayFrame->Lower();

        while ( pFrame )
        {
            if ( pFrame->IsLayoutFrame() )
                lcl_InvalidateAllLowersPrt( static_cast<SwLayoutFrame*>(pFrame) );
            else
            {
                pFrame->InvalidatePrt_();
                pFrame->InvalidateSize_();
                pFrame->SetCompletePaint();
            }

            pFrame = pFrame->GetNext();
        }
    }

    bool SwContentFrame::CalcLowers( SwLayoutFrame* pLay, const SwLayoutFrame* pDontLeave,
                                     long nBottom, bool bSkipRowSpanCells )
    {
        if ( !pLay )
            return true;

        vcl::RenderContext* pRenderContext = pLay->getRootFrame()->GetCurrShell()->GetOut();
        // LONG_MAX == nBottom means we have to calculate all
        bool bAll = LONG_MAX == nBottom;
        bool bRet = false;
        SwContentFrame *pCnt = pLay->ContainsContent();
        SwRectFnSet aRectFnSet(pLay);

        // FME 2007-08-30 #i81146# new loop control
        int nLoopControlRuns = 0;
        const int nLoopControlMax = 10;
        const SwModify* pLoopControlCond = nullptr;

        while ( pCnt && pDontLeave->IsAnLower( pCnt ) )
        {
            // #115759# - check, if a format of content frame is
            // possible. Thus, 'copy' conditions, found at the beginning of
            // <SwContentFrame::MakeAll(..)>, and check these.
            const bool bFormatPossible = !pCnt->IsJoinLocked() &&
                                         ( !pCnt->IsTextFrame() ||
                                           !static_cast<SwTextFrame*>(pCnt)->IsLocked() ) &&
                                         ( pCnt->IsFollow() || !StackHack::IsLocked() );

            // NEW TABLES
            bool bSkipContent = false;
            if ( bSkipRowSpanCells && pCnt->IsInTab() )
            {
                const SwFrame* pCell = pCnt->GetUpper();
                while ( pCell && !pCell->IsCellFrame() )
                    pCell = pCell->GetUpper();
                if ( pCell && 1 != static_cast<const SwCellFrame*>( pCell )->GetLayoutRowSpan() )
                    bSkipContent = true;
            }

            if ( bFormatPossible && !bSkipContent )
            {
                bRet |= !pCnt->isFrameAreaDefinitionValid();
                // #i26945# - no extra invalidation of floating
                // screen objects needed.
                // Thus, delete call of method <SwFrame::InvalidateObjs( true )>
                pCnt->Calc(pRenderContext);
                // OD 2004-05-11 #i28701# - usage of new method <::FormatObjsAtFrame(..)>
                // to format the floating screen objects
                // #i46941# - frame has to be valid
                // Note: frame could be invalid after calling its format, if it's locked.
                OSL_ENSURE( !pCnt->IsTextFrame() ||
                        pCnt->isFrameAreaDefinitionValid() ||
                        static_cast<SwTextFrame*>(pCnt)->IsJoinLocked(),
                        "<SwContentFrame::CalcLowers(..)> - text frame invalid and not locked." );
                if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
                {
                    // #i23129#, #i36347# - pass correct page frame to
                    // the object formatter
                    if ( !SwObjectFormatter::FormatObjsAtFrame( *pCnt,
                                                              *(pCnt->FindPageFrame()) ) )
                    {
                        SwTextNode const*const pTextNode(
                            static_cast<SwTextFrame*>(pCnt)->GetTextNodeFirst());
                        if (pTextNode == pLoopControlCond)
                            ++nLoopControlRuns;
                        else
                        {
                            nLoopControlRuns = 0;
                            pLoopControlCond = pTextNode;
                        }

                        if ( nLoopControlRuns < nLoopControlMax )
                        {
                            // restart format with first content
                            pCnt = pLay->ContainsContent();
                            continue;
                        }

    #if OSL_DEBUG_LEVEL > 1
                        OSL_FAIL( "LoopControl in SwContentFrame::CalcLowers" );
    #endif
                    }
                }
                pCnt->GetUpper()->Calc(pRenderContext);
            }
            if( ! bAll && aRectFnSet.YDiff(aRectFnSet.GetTop(pCnt->getFrameArea()), nBottom) > 0 )
                break;
            pCnt = pCnt->GetNextContentFrame();
        }
        return bRet;
    }

    // #i26945# - add parameter <_bOnlyRowsAndCells> to control
    // that only row and cell frames are formatted.
    static bool lcl_InnerCalcLayout( SwFrame *pFrame,
                                          long nBottom,
                                          bool _bOnlyRowsAndCells )
    {
        vcl::RenderContext* pRenderContext = pFrame->getRootFrame()->GetCurrShell() ? pFrame->getRootFrame()->GetCurrShell()->GetOut() : nullptr;
        // LONG_MAX == nBottom means we have to calculate all
        bool bAll = LONG_MAX == nBottom;
        bool bRet = false;
        const SwFrame* pOldUp = pFrame->GetUpper();
        SwRectFnSet aRectFnSet(pFrame);
        do
        {
            // #i26945# - parameter <_bOnlyRowsAndCells> controls,
            // if only row and cell frames are formatted.
            if ( pFrame->IsLayoutFrame() &&
                 ( !_bOnlyRowsAndCells || pFrame->IsRowFrame() || pFrame->IsCellFrame() ) )
            {
                // #130744# An invalid locked table frame will
                // not be calculated => It will not become valid =>
                // Loop in lcl_RecalcRow(). Therefore we do not consider them for bRet.
                bRet |= !pFrame->isFrameAreaDefinitionValid() && ( !pFrame->IsTabFrame() || !static_cast<SwTabFrame*>(pFrame)->IsJoinLocked() );
                pFrame->Calc(pRenderContext);
                if( static_cast<SwLayoutFrame*>(pFrame)->Lower() )
                    bRet |= lcl_InnerCalcLayout( static_cast<SwLayoutFrame*>(pFrame)->Lower(), nBottom);

                // NEW TABLES
                SwCellFrame* pThisCell = dynamic_cast<SwCellFrame*>(pFrame);
                if ( pThisCell && pThisCell->GetTabBox()->getRowSpan() < 1 )
                {
                    SwCellFrame& rToCalc = const_cast<SwCellFrame&>(pThisCell->FindStartEndOfRowSpanCell( true ));
                    bRet |= !rToCalc.isFrameAreaDefinitionValid();
                    rToCalc.Calc(pRenderContext);
                    if ( rToCalc.Lower() )
                        bRet |= lcl_InnerCalcLayout( rToCalc.Lower(), nBottom);
                }
            }
            pFrame = pFrame->GetNext();
        } while( pFrame &&
                ( bAll ||
                  aRectFnSet.YDiff(aRectFnSet.GetTop(pFrame->getFrameArea()), nBottom) < 0 )
                && pFrame->GetUpper() == pOldUp );
        return bRet;
    }

    static void lcl_RecalcRow( SwRowFrame* pRow, long nBottom )
    {
        // FME 2007-08-30 #i81146# new loop control
        int nLoopControlRuns_1 = 0;
        sal_uInt16 nLoopControlStage_1 = 0;
        const int nLoopControlMax = 10;

        bool bCheck = true;
        do
        {
            // FME 2007-08-30 #i81146# new loop control
            int nLoopControlRuns_2 = 0;
            sal_uInt16 nLoopControlStage_2 = 0;

            while( lcl_InnerCalcLayout( pRow, nBottom ) )
            {
                if ( ++nLoopControlRuns_2 > nLoopControlMax )
                {
                    SAL_WARN_IF(nLoopControlStage_2 == 0, "sw.layout", "LoopControl_2 in lcl_RecalcRow: Stage 1!");
                    SAL_WARN_IF(nLoopControlStage_2 == 1, "sw.layout", "LoopControl_2 in lcl_RecalcRow: Stage 2!!");
                    SAL_WARN_IF(nLoopControlStage_2 >= 2, "sw.layout", "LoopControl_2 in lcl_RecalcRow: Stage 3!!!");
                    pRow->ValidateThisAndAllLowers( nLoopControlStage_2++ );
                    nLoopControlRuns_2 = 0;
                    if( nLoopControlStage_2 > 2 )
                        break;
                }

                bCheck = true;
            }

            if( bCheck )
            {
                // #115759# - force another format of the
                // lowers, if at least one of it was invalid.

                // tdf#114306 writer may crash because pRow points to a deleted SwRowFrame
                SwRowFrame* pOriginalRow = pRow;
                OSL_ENSURE(pOriginalRow->GetUpper() && pOriginalRow->GetUpper()->IsTabFrame(), "No table");
                SwTabFrame* pOriginalTab = static_cast<SwTabFrame*>(pRow->GetUpper());

                bCheck = SwContentFrame::CalcLowers( pRow, pRow->GetUpper(), nBottom, true );

                bool bRowStillExists = false;
                SwFrame* pTestRow = pOriginalTab->Lower();

                while (pTestRow)
                {
                    if (pTestRow == pRow)
                    {
                        bRowStillExists = true;
                        break;
                    }
                    pTestRow = pTestRow->GetNext();
                }

                if (!bRowStillExists)
                {
                    SAL_WARN("sw.layout", "no row anymore at " << pRow);
                    return;
                }

                // NEW TABLES
                // First we calculate the cells with row span of < 1, afterwards
                // all cells with row span of > 1:
                for ( int i = 0; i < 2; ++i )
                {
                    SwCellFrame* pCellFrame = static_cast<SwCellFrame*>(pRow->Lower());
                    while ( pCellFrame )
                    {
                        const bool bCalc = 0 == i ?
                                           pCellFrame->GetLayoutRowSpan() < 1 :
                                           pCellFrame->GetLayoutRowSpan() > 1;

                        if ( bCalc )
                        {
                            SwCellFrame& rToRecalc = 0 == i ?
                                                   const_cast<SwCellFrame&>(pCellFrame->FindStartEndOfRowSpanCell( true )) :
                                                   *pCellFrame;
                            bCheck  |= SwContentFrame::CalcLowers( &rToRecalc, &rToRecalc, nBottom, false );
                        }

                        pCellFrame = static_cast<SwCellFrame*>(pCellFrame->GetNext());
                    }
                }

                if ( bCheck )
                {
                    if ( ++nLoopControlRuns_1 > nLoopControlMax )
                    {
                        SAL_WARN_IF(nLoopControlStage_1 == 0, "sw.layout", "LoopControl_1 in lcl_RecalcRow: Stage 1!");
                        SAL_WARN_IF(nLoopControlStage_1 == 1, "sw.layout", "LoopControl_1 in lcl_RecalcRow: Stage 2!!");
                        SAL_WARN_IF(nLoopControlStage_1 >= 2, "sw.layout", "LoopControl_1 in lcl_RecalcRow: Stage 3!!!");
                        pRow->ValidateThisAndAllLowers( nLoopControlStage_1++ );
                        nLoopControlRuns_1 = 0;
                        if( nLoopControlStage_1 > 2 )
                            break;
                    }

                    continue;
                }
            }
            break;
        } while( true );
    }

    static void lcl_RecalcTable( SwTabFrame& rTab,
                                      SwLayoutFrame *pFirstRow,
                                      SwLayNotify &rNotify )
    {
        if ( rTab.Lower() )
        {
            if ( !pFirstRow )
            {
                pFirstRow = static_cast<SwLayoutFrame*>(rTab.Lower());
                rNotify.SetLowersComplete( true );
            }
            ::SwInvalidatePositions( pFirstRow, LONG_MAX );
            lcl_RecalcRow( static_cast<SwRowFrame*>(pFirstRow), LONG_MAX );
        }
    }

    // This is a new function to check the first condition whether
    // a tab frame may move backward. It replaces the formerly used
    // GetIndPrev(), which did not work correctly for #i5947#
    static bool lcl_NoPrev( const SwFrame& rFrame )
    {
        // #i79774#
        // skip empty sections on investigation of direct previous frame.
        // use information, that at least one empty section is skipped in the following code.
        bool bSkippedDirectPrevEmptySection( false );
        if ( rFrame.GetPrev() )
        {
            const SwFrame* pPrev( rFrame.GetPrev() );
            while ( pPrev &&
                    pPrev->IsSctFrame() &&
                    !dynamic_cast<const SwSectionFrame&>(*pPrev).GetSection() )
            {
                pPrev = pPrev->GetPrev();
                bSkippedDirectPrevEmptySection = true;
            }
            if ( pPrev )
            {
                return false;
            }
        }

        if ( ( !bSkippedDirectPrevEmptySection && !rFrame.GetIndPrev() ) ||
             ( bSkippedDirectPrevEmptySection &&
               ( !rFrame.IsInSct() || !rFrame.GetIndPrev_() ) ) )
        {
            return true;
        }

        // I do not have a direct prev, but I have an indirect prev.
        // In section frames I have to check if I'm located inside
        // the first column:
        if ( rFrame.IsInSct() )
        {
            const SwFrame* pSct = rFrame.GetUpper();
            if ( pSct && pSct->IsColBodyFrame() &&
                 pSct->GetUpper()->GetUpper()->IsSctFrame() )
            {
                const SwFrame* pPrevCol = rFrame.GetUpper()->GetUpper()->GetPrev();
                if ( pPrevCol )
                    // I'm not inside the first column and do not have a direct
                    // prev. I can try to go backward.
                    return true;
            }
        }

        return false;
    }

    #define KEEPTAB ( !GetFollow() && !IsFollow() )

    // - helper method to find next content frame of
    // a table frame and format it to assure keep attribute.
    // method return true, if a next content frame is formatted.
    // Precondition: The given table frame hasn't a follow and isn't a follow.
    SwFrame* sw_FormatNextContentForKeep( SwTabFrame* pTabFrame )
    {
        vcl::RenderContext* pRenderContext = pTabFrame->getRootFrame()->GetCurrShell()->GetOut();
        // find next content, table or section
        SwFrame* pNxt = pTabFrame->FindNext();

        // skip empty sections
        while ( pNxt && pNxt->IsSctFrame() &&
                !static_cast<SwSectionFrame*>(pNxt)->GetSection() )
        {
            pNxt = pNxt->FindNext();
        }

        // if found next frame is a section, get its first content.
        if ( pNxt && pNxt->IsSctFrame() )
        {
            pNxt = static_cast<SwSectionFrame*>(pNxt)->ContainsAny();
        }

        // format found next frame.
        // if table frame is inside another table, method <SwFrame::MakeAll()> is
        // called to avoid that the superior table frame is formatted.
        if ( pNxt )
        {
            if ( pTabFrame->GetUpper()->IsInTab() )
                pNxt->MakeAll(pNxt->getRootFrame()->GetCurrShell()->GetOut());
            else
                pNxt->Calc(pRenderContext);
        }

        return pNxt;
    }

    namespace {
        bool AreAllRowsKeepWithNext( const SwRowFrame* pFirstRowFrame, const bool bCheckParents = true  )
        {
            bool bRet = pFirstRowFrame != nullptr &&
                        pFirstRowFrame->ShouldRowKeepWithNext( bCheckParents );

            while ( bRet && pFirstRowFrame->GetNext() != nullptr )
            {
                pFirstRowFrame = dynamic_cast<const SwRowFrame*>(pFirstRowFrame->GetNext());
                bRet = pFirstRowFrame != nullptr &&
                       pFirstRowFrame->ShouldRowKeepWithNext( bCheckParents );
            }

            return bRet;
        }
    }
    void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext)
    {
        if ( IsJoinLocked() || StackHack::IsLocked() || StackHack::Count() > 50 )
            return;

        if ( HasFollow() )
        {
            SwTabFrame* pFollowFrame = GetFollow();
            OSL_ENSURE( !pFollowFrame->IsJoinLocked() || !pFollowFrame->IsRebuildLastLine(),
                    "SwTabFrame::MakeAll for master while follow is in RebuildLastLine()" );
            if ( pFollowFrame->IsJoinLocked() && pFollowFrame->IsRebuildLastLine() )
                return;
        }

        PROTOCOL_ENTER( this, PROT::MakeAll, DbgAction::NONE, nullptr )

        LockJoin(); //I don't want to be destroyed on the way.
        SwLayNotify aNotify( this );    //does the notification in the DTor
        // If pos is invalid, we have to call a SetInvaKeep at aNotify.
        // Otherwise the keep attribute would not work in front of a table.
        const bool bOldValidPos = isFrameAreaPositionValid();

        //If my neighbour is my Follow at the same time, I'll swallow it up.
        // OD 09.04.2003 #108698# - join all follows, which are placed on the
        // same page/column.
        // OD 29.04.2003 #109213# - join follow, only if join for the follow
        // is not locked. Otherwise, join will not be performed and this loop
        // will be endless.
        while ( GetNext() && GetNext() == GetFollow() &&
                !GetFollow()->IsJoinLocked()
              )
        {
            if ( HasFollowFlowLine() )
                RemoveFollowFlowLine();
            Join();
        }

        // The bRemoveFollowFlowLinePending is set if the split attribute of the
        // last line is set:
        if ( IsRemoveFollowFlowLinePending() && HasFollowFlowLine() )
        {
            if ( RemoveFollowFlowLine() )
                Join();
            SetRemoveFollowFlowLinePending( false );
        }

        if (m_bResizeHTMLTable) //Optimized interplay with grow/shrink of the content
        {
            m_bResizeHTMLTable = false;
            SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout();
            if ( pLayout )
                m_bCalcLowers = pLayout->Resize(
                                pLayout->GetBrowseWidthByTabFrame( *this ) );
        }

        // as long as bMakePage is true, a new page can be created (exactly once)
        bool bMakePage = true;
        // bMovedBwd gets set to true when the frame flows backwards
        bool bMovedBwd = false;
        // as long as bMovedFwd is false, the Frame may flow backwards (until
        // it has been moved forward once)
        bool bMovedFwd  = false;
        // gets set to true when the Frame is split
        bool bSplit = false;
        const bool bFootnotesInDoc = !GetFormat()->GetDoc()->GetFootnoteIdxs().empty();
        const bool bFly     = IsInFly();

        auto pAccess = o3tl::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
        const SwBorderAttrs *pAttrs = pAccess->Get();

        const bool bLargeTable = GetTable()->GetTabLines().size() > 64;  //arbitrary value, virtually guaranteed to be larger than one page.
        const bool bEmulateTableKeep = !bLargeTable && AreAllRowsKeepWithNext( GetFirstNonHeadlineRow(), /*bCheckParents=*/false );
        // The beloved keep attribute
        const bool bKeep = IsKeep(pAttrs->GetAttrSet().GetKeep(), GetBreakItem(), bEmulateTableKeep);

        // All rows should keep together
        const bool bDontSplit = !IsFollow() &&
                                ( !GetFormat()->GetLayoutSplit().GetValue() );

        // The number of repeated headlines
        const sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat();

        // This flag indicates that we are allowed to try to split the
        // table rows.
        bool bTryToSplit = true;

        // Indicates that two individual rows may keep together, based on the keep
        // attribute set at the first paragraph in the first cell.
        const bool bTableRowKeep = !bDontSplit && GetFormat()->GetDoc()->GetDocumentSettingManager().get(DocumentSettingId::TABLE_ROW_KEEP);

        // The Magic Move: Used for the table row keep feature.
        // If only the last row of the table wants to keep (implicitly by setting
        // keep for the first paragraph in the first cell), and this table does
        // not have a next, the last line will be cut. Loop prevention: Only
        // one try.
        // WHAT IS THIS??? It "magically" hides last line (paragraph) in a table,
        // if first is set to keep with next???
        bool bLastRowHasToMoveToFollow = false;
        bool bLastRowMoveNoMoreTries = false;

        // Join follow table, if this table is not allowed to split:
        if ( bDontSplit )
        {
            while ( GetFollow() && !GetFollow()->IsJoinLocked() )
            {
                if ( HasFollowFlowLine() )
                    RemoveFollowFlowLine();
                Join();
            }
        }

        // Join follow table, if this does not have enough (repeated) lines:
        if ( nRepeat )
        {
            if( GetFollow() && !GetFollow()->IsJoinLocked() &&
                nullptr == GetFirstNonHeadlineRow() )
            {
                if ( HasFollowFlowLine() )
                    RemoveFollowFlowLine();
                Join();
            }
        }

        // Join follow table, if last row of this table should keep:
        if ( bTableRowKeep && GetFollow() && !GetFollow()->IsJoinLocked() )
        {
            const SwRowFrame* pTmpRow = static_cast<const SwRowFrame*>(GetLastLower());
            if ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() )
            {
                if ( HasFollowFlowLine() )
                    RemoveFollowFlowLine();
                Join();
            }
        }

        // a new one is moved forwards immediately
        if ( !getFrameArea().Top() && IsFollow() )
        {
            SwFrame *pPre = GetPrev();
            if ( pPre && pPre->IsTabFrame() && static_cast<SwTabFrame*>(pPre)->GetFollow() == this)
            {
                if ( !MoveFwd( bMakePage, false ) )
                    bMakePage = false;
                bMovedFwd = true;
            }
        }

        int nUnSplitted = 5; // Just another loop control :-(
        int nThrowAwayValidLayoutLimit = 5; // And another one :-(
        SwRectFnSet aRectFnSet(this);
        while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
        {
            const bool bMoveable = IsMoveable();
            if (bMoveable &&
                !(bMovedFwd && bEmulateTableKeep) )
                if ( CheckMoveFwd( bMakePage, bKeep && KEEPTAB, bEmulateTableKeep ) )
                {
                    bMovedFwd = true;
                    m_bCalcLowers = true;
                    // #i99267#
                    // reset <bSplit> after forward move to assure that follows
                    // can be joined, if further space is available.
                    bSplit = false;
                }

            Point aOldPos( aRectFnSet.GetPos(getFrameArea()) );
            MakePos();

            if ( aOldPos != aRectFnSet.GetPos(getFrameArea()) )
            {
                if ( aOldPos.Y() != aRectFnSet.GetTop(getFrameArea()) )
                {
                    SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout();
                    if( pLayout )
                    {
                        pAccess.reset();
                        m_bCalcLowers |= pLayout->Resize(
                            pLayout->GetBrowseWidthByTabFrame( *this ) );
                        pAccess = o3tl::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
                        pAttrs = pAccess->Get();
                    }

                    setFramePrintAreaValid(false);
                    aNotify.SetLowersComplete( false );
                }
                SwFrame *pPre;
                if ( bKeep || (nullptr != (pPre = FindPrev()) &&
                    pPre->GetAttrSet()->GetKeep().GetValue()) )
                {
                    m_bCalcLowers = true;
                }
            }

            //We need to know the height of the first row, because the master needs
            //to be activated if it shrinks and then absorb the row if necessary.
            long n1StLineHeight = 0;
            if ( IsFollow() )
            {
                SwFrame* pFrame = GetFirstNonHeadlineRow();
                if ( pFrame )
                    n1StLineHeight = aRectFnSet.GetHeight(pFrame->getFrameArea());
            }

            if ( !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
            {
                const long nOldPrtWidth = aRectFnSet.GetWidth(getFramePrintArea());
                const long nOldFrameWidth = aRectFnSet.GetWidth(getFrameArea());
                const Point aOldPrtPos  = aRectFnSet.GetPos(getFramePrintArea());
                Format( getRootFrame()->GetCurrShell()->GetOut(), pAttrs );

                SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout();
                if ( pLayout &&
                    (aRectFnSet.GetWidth(getFramePrintArea()) != nOldPrtWidth ||
                    aRectFnSet.GetWidth(getFrameArea()) != nOldFrameWidth) )
                {
                    pAccess.reset();
                    m_bCalcLowers |= pLayout->Resize(
                        pLayout->GetBrowseWidthByTabFrame( *this ) );
                    pAccess = o3tl::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
                    pAttrs = pAccess->Get();
                }
                if ( aOldPrtPos != aRectFnSet.GetPos(getFramePrintArea()) )
                    aNotify.SetLowersComplete( false );
            }

            // If this is the first one in a chain, check if this can flow
            // backwards (if this is movable at all).
            // To prevent oscillations/loops, check that this has not just
            // flowed forwards.
            if ( !bMovedFwd && (bMoveable || bFly) && lcl_NoPrev( *this ) )
            {
                // for Follows notify Master.
                // only move Follow if it has to skip empty pages.
                if ( IsFollow() )
                {
                    // Only if the height of the first line got smaller.
                    SwFrame *pFrame = GetFirstNonHeadlineRow();
                    if( pFrame && n1StLineHeight >aRectFnSet.GetHeight(pFrame->getFrameArea()) )
                    {
                        SwTabFrame *pMaster = FindMaster();
                        bool bDummy;
                        if ( ShouldBwdMoved( pMaster->GetUpper(), false, bDummy ) )
                            pMaster->InvalidatePos();
                    }
                }
                SwFootnoteBossFrame *pOldBoss = bFootnotesInDoc ? FindFootnoteBossFrame( true ) : nullptr;
                bool bReformat;
                if ( MoveBwd( bReformat ) )
                {
                    aRectFnSet.Refresh(this);
                    bMovedBwd = true;
                    aNotify.SetLowersComplete( false );
                    if ( bFootnotesInDoc )
                        MoveLowerFootnotes( nullptr, pOldBoss, nullptr, true );
                    if ( bReformat || bKeep )
                    {
                        long nOldTop = aRectFnSet.GetTop(getFrameArea());
                        MakePos();
                        if( nOldTop != aRectFnSet.GetTop(getFrameArea()) )
                        {
                            SwHTMLTableLayout *pHTMLLayout =
                                GetTable()->GetHTMLTableLayout();
                            if( pHTMLLayout )
                            {
                                pAccess.reset();
                                m_bCalcLowers |= pHTMLLayout->Resize(
                                    pHTMLLayout->GetBrowseWidthByTabFrame( *this ) );

                                pAccess = o3tl::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
                                pAttrs = pAccess->Get();
                            }

                            setFramePrintAreaValid(false);
                            Format( getRootFrame()->GetCurrShell()->GetOut(), pAttrs );
                        }
                        lcl_RecalcTable( *this, nullptr, aNotify );
                        m_bLowersFormatted = true;
                        if ( bKeep && KEEPTAB )
                        {

                            // Consider case that table is inside another table,
                            // because it has to be avoided, that superior table
                            // is formatted.
                            // Thus, find next content, table or section
                            // and, if a section is found, get its first
                            // content.
                            if ( nullptr != sw_FormatNextContentForKeep( this ) && !GetNext() )
                            {
                                setFrameAreaPositionValid(false);
                            }
                        }
                    }
                }
            }

            //Again an invalid value? - do it again...
            if ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
                continue;

            // check, if calculation of table frame is ready.

            // Local variable <nDistanceToUpperPrtBottom>
            //     Introduce local variable and init it with the distance from the
            //     table frame bottom to the bottom of the upper printing area.
            // Note: negative values denotes the situation that table frame doesn't fit in its upper.
            SwTwips nDistanceToUpperPrtBottom =
                    aRectFnSet.BottomDist(getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()));

            /// In online layout try to grow upper of table frame, if table frame doesn't fit in its upper.
            const SwViewShell *pSh = getRootFrame()->GetCurrShell();
            const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
            if ( nDistanceToUpperPrtBottom < 0 && bBrowseMode )
            {
                if ( GetUpper()->Grow( -nDistanceToUpperPrtBottom ) )
                {
                    // upper is grown --> recalculate <nDistanceToUpperPrtBottom>
                    nDistanceToUpperPrtBottom = aRectFnSet.BottomDist(getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()));
                }
            }

            // If there is still some space left in the upper, we check if we
            // can join some rows of the follow.
            // Setting bLastRowHasToMoveToFollow to true means we want to force
            // the table to be split! Only skip this if condition once.
            if( nDistanceToUpperPrtBottom >= 0 && !bLastRowHasToMoveToFollow )
            {
                // If there is space left in the upper printing area, join as for trial
                // at least one further row of an existing follow.
                if ( !bSplit && GetFollow() )
                {
                    bool bDummy;
                    if ( GetFollow()->ShouldBwdMoved( GetUpper(), false, bDummy ) )
                    {
                        SwFrame *pTmp = GetUpper();
                        SwTwips nDeadLine = aRectFnSet.GetPrtBottom(*pTmp);
                        if ( bBrowseMode )
                            nDeadLine += pTmp->Grow( LONG_MAX, true );
                        bool bFits = aRectFnSet.BottomDist(getFrameArea(), nDeadLine) > 0;
                        if (!bFits && aRectFnSet.GetHeight(GetFollow()->getFrameArea()) == 0)
                            // The follow should move backwards, so allow the case
                            // when the upper has no space, but the follow is
                            // empty.
                            bFits = aRectFnSet.BottomDist(getFrameArea(), nDeadLine) >= 0;
                        if (bFits)
                        {
                            // First, we remove an existing follow flow line.
                            if ( HasFollowFlowLine() )
                            {
                                SwFrame* pLastLine = GetLastLower();
                                RemoveFollowFlowLine();
                                // invalidate and rebuild last row
                                if ( pLastLine )
                                {
                                    ::SwInvalidateAll( pLastLine, LONG_MAX );
                                    SetRebuildLastLine( true );
                                    lcl_RecalcRow( static_cast<SwRowFrame*>(pLastLine), LONG_MAX );
                                    SetRebuildLastLine( false );
                                }

                                SwFrame* pRow = GetFollow()->GetFirstNonHeadlineRow();

                                if ( !pRow || !pRow->GetNext() )
                                    //The follow becomes empty and invalid for this reason.
                                    Join();

                                continue;
                            }

                            // If there is no follow flow line, we move the first
                            // row in the follow table to the master table.
                            SwRowFrame *pRow = GetFollow()->GetFirstNonHeadlineRow();

                            //The follow becomes empty and invalid for this reason.
                            if ( !pRow )
                            {
                                Join();
                                continue;
                            }

                            const SwTwips nOld = aRectFnSet.GetHeight(getFrameArea());
                            long nRowsToMove = lcl_GetMaximumLayoutRowSpan( *pRow );
                            SwFrame* pRowToMove = pRow;

                            while ( pRowToMove && nRowsToMove-- > 0 )
                            {
                                const bool bMoveFootnotes = bFootnotesInDoc && !GetFollow()->IsJoinLocked();

                                SwFootnoteBossFrame *pOldBoss = nullptr;
                                if ( bMoveFootnotes )
                                    pOldBoss = pRowToMove->FindFootnoteBossFrame( true );

                                SwFrame* pNextRow = pRowToMove->GetNext();

                                if ( !pNextRow )
                                {
                                    //The follow becomes empty and invalid for this reason.
                                    Join();
                                }
                                else
                                {
                                    pRowToMove->Cut();
                                    pRowToMove->Paste( this );
                                }

                                //Displace the footnotes!
                                if ( bMoveFootnotes )
                                    if ( static_cast<SwLayoutFrame*>(pRowToMove)->MoveLowerFootnotes( nullptr, pOldBoss, FindFootnoteBossFrame( true ), true ) )
                                        GetUpper()->Calc(pRenderContext);

                                pRowToMove = pNextRow;
                            }

                            if ( nOld != aRectFnSet.GetHeight(getFrameArea()) )
                                lcl_RecalcTable( *this, static_cast<SwLayoutFrame*>(pRow), aNotify );

                            continue;
                        }
                    }
                }
                else if ( KEEPTAB )
                {
                    bool bFormat = false;
                    if ( bKeep )
                        bFormat = true;
                    else if ( bTableRowKeep && !bLastRowMoveNoMoreTries )
                    {
                        // We only want to give the last row one chance to move
                        // to the follow table. Set the flag as early as possible:
                        bLastRowMoveNoMoreTries = true;

                        // The last line of the table has to be cut off if:
                        // 1. The table does not want to keep with its next
                        // 2. The compatibility option is set and the table is allowed to split
                        // 3. We did not already cut off the last row
                        // 4. There is not break after attribute set at the table
                        // 5. There is no break before attribute set behind the table
                        // 6. There is no section change behind the table (see IsKeep)
                        // 7. The last table row wants to keep with its next.
                        const SwRowFrame* pLastRow = static_cast<const SwRowFrame*>(GetLastLower());
                        if (pLastRow
                            && IsKeep(pAttrs->GetAttrSet().GetKeep(), GetBreakItem(), true)
                            && pLastRow->ShouldRowKeepWithNext())
                        {
                            bFormat = true;
                        }
                    }

                    if ( bFormat )
                    {
                        pAccess.reset();

                        // Consider case that table is inside another table, because
                        // it has to be avoided, that superior table is formatted.
                        // Thus, find next content, table or section and, if a section
                        // is found, get its first content.
                        const SwFrame* pTmpNxt = sw_FormatNextContentForKeep( this );

                        pAccess = o3tl::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
                        pAttrs = pAccess->Get();

                        // The last row wants to keep with the frame behind the table.
                        // Check if the next frame is on a different page and valid.
                        // In this case we do a magic trick:
                        if ( !bKeep && !GetNext() && pTmpNxt && pTmpNxt->isFrameAreaDefinitionValid() )
                        {
                            setFrameAreaPositionValid(false);
                            bLastRowHasToMoveToFollow = true;
                        }
                    }
                }

                if ( isFrameAreaDefinitionValid() )
                {
                    if (m_bCalcLowers)
                    {
                        lcl_RecalcTable( *this, nullptr, aNotify );
                        m_bLowersFormatted = true;
                        m_bCalcLowers = false;
                    }
                    else if (m_bONECalcLowers)
                    {
                        lcl_RecalcRow( static_cast<SwRowFrame*>(Lower()), LONG_MAX );
                        m_bONECalcLowers = false;
                    }
                }
                continue;
            }

            //I don't fit in the higher-ranked element anymore, therefore it's the
            //right moment to do some preferably constructive changes.

            //If I'm NOT allowed to leave the parent Frame, I've got a problem.
            // Following Arthur Dent, we do the only thing that you can do with
            // an unsolvable problem: We ignore it with all our power.
            if ( !bMoveable )
            {
                if (m_bCalcLowers && isFrameAreaDefinitionValid())
                {
                    lcl_RecalcTable( *this, nullptr, aNotify );
                    m_bLowersFormatted = true;
                    m_bCalcLowers = false;
                }
                else if (m_bONECalcLowers)
                {
                    lcl_RecalcRow( static_cast<SwRowFrame*>(Lower()), LONG_MAX );
                    m_bONECalcLowers = false;
                }

                // It does not make sense to cut off the last line if we are
                // not moveable:
                bLastRowHasToMoveToFollow = false;

                continue;
            }

            if (m_bCalcLowers && isFrameAreaDefinitionValid())
            {
                lcl_RecalcTable( *this, nullptr, aNotify );
                m_bLowersFormatted = true;
                m_bCalcLowers = false;
                if( !isFrameAreaDefinitionValid() )
                    continue;
            }

            // First try to split the table. Condition:
            // 1. We have at least one non headline row
            // 2. If this row wants to keep, we need an additional row
            // 3. The table is allowed to split or we do not have an pIndPrev:
            SwFrame* pIndPrev = GetIndPrev();
            const SwRowFrame* pFirstNonHeadlineRow = GetFirstNonHeadlineRow();
            // #i120016# if this row wants to keep, allow split in case that all rows want to keep with next,
            // the table can not move forward as it is the first one and a split is in general allowed.
            const bool bAllowSplitOfRow = ( bTableRowKeep &&
                                            AreAllRowsKeepWithNext( pFirstNonHeadlineRow ) ) &&
                                          !pIndPrev &&
                                          !bDontSplit;
            const bool bEmulateTableKeepFwdMoveAllowed = IsKeepFwdMoveAllowed(bEmulateTableKeep);

            if ( pFirstNonHeadlineRow && nUnSplitted > 0 &&
                 ( !bEmulateTableKeepFwdMoveAllowed ||
                   ( ( !bTableRowKeep || pFirstNonHeadlineRow->GetNext() ||
                       !pFirstNonHeadlineRow->ShouldRowKeepWithNext() || bAllowSplitOfRow
                     ) && ( !bDontSplit || !pIndPrev )
               ) ) )
            {
                // #i29438#
                // Special DoNotSplit cases:
                // We better avoid splitting if the table keeps with next paragraph and can move fwd still.
                // We better avoid splitting of a row frame if we are inside a columned
                // section which has a height of 0, because this is not growable and thus
                // all kinds of unexpected things could happen.
                if ( !bEmulateTableKeepFwdMoveAllowed ||
                     ( IsInSct() && FindSctFrame()->Lower()->IsColumnFrame() &&
                       0 == aRectFnSet.GetHeight(GetUpper()->getFrameArea())
                   ) )
                {
                    bTryToSplit = false;
                }

                // 1. Try: bTryToSplit = true  => Try to split the row.
                // 2. Try: bTryToSplit = false => Split the table between the rows.
                if ( pFirstNonHeadlineRow->GetNext() || bTryToSplit )
                {
                    SwTwips nDeadLine = aRectFnSet.GetPrtBottom(*GetUpper());
                    if( IsInSct() || GetUpper()->IsInTab() ) // TABLE IN TABLE)
                        nDeadLine = aRectFnSet.YInc( nDeadLine,
                                            GetUpper()->Grow( LONG_MAX, true ) );

                    {
                        SetInRecalcLowerRow( true );
                        ::lcl_RecalcRow( static_cast<SwRowFrame*>(Lower()), nDeadLine );
                        SetInRecalcLowerRow( false );
                    }
                    m_bLowersFormatted = true;
                    aNotify.SetLowersComplete( true );

                    // One more check if its really necessary to split the table.
                    // 1. The table either has to exceed the deadline or
                    // 2. We explicitly want to cut off the last row.
                    if( aRectFnSet.BottomDist( getFrameArea(), nDeadLine ) > 0 && !bLastRowHasToMoveToFollow )
                    {
                        continue;
                    }

                    // Set to false again as early as possible.
                    bLastRowHasToMoveToFollow = false;

                    // #i52781#
                    // YaSC - Yet another special case:
                    // If our upper is inside a table cell which is not allowed
                    // to split, we do not try to split:
                    if ( GetUpper()->IsInTab() )
                    {
                        const SwFrame* pTmpRow = GetUpper();
                        while ( pTmpRow && !pTmpRow->IsRowFrame() )
                           pTmpRow = pTmpRow->GetUpper();
                        if ( pTmpRow && !static_cast<const SwRowFrame*>(pTmpRow)->IsRowSplitAllowed() )
                            continue;
                    }

                    sal_uInt16 nMinNumOfLines = nRepeat;

                    if ( bTableRowKeep )
                    {
                        const SwRowFrame* pTmpRow = GetFirstNonHeadlineRow();
                        while ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() )
                        {
                            ++nMinNumOfLines;
                            pTmpRow = static_cast<const SwRowFrame*>(pTmpRow->GetNext());
                        }
                    }

                    if ( !bTryToSplit )
                        ++nMinNumOfLines;

                    const SwTwips nBreakLine = aRectFnSet.YInc(
                            aRectFnSet.GetTop(getFrameArea()),
                            aRectFnSet.GetTopMargin(*this) +
                             lcl_GetHeightOfRows( GetLower(), nMinNumOfLines ) );

                    // Some more checks if we want to call the split algorithm or not:
                    // The repeating lines / keeping lines still fit into the upper or
                    // if we do not have an (in)direct Prev, we split anyway.
                    if( aRectFnSet.YDiff(nDeadLine, nBreakLine) >=0
                        || !pIndPrev || !bEmulateTableKeepFwdMoveAllowed )
                    {
                        aNotify.SetLowersComplete( false );
                        bSplit = true;

                        // An existing follow flow line has to be removed.
                        if ( HasFollowFlowLine() )
                        {
                            if (!nThrowAwayValidLayoutLimit)
                                continue;
                            const bool bInitialLoopEndCondition(isFrameAreaDefinitionValid());
                            RemoveFollowFlowLine();
                            const bool bFinalLoopEndCondition(isFrameAreaDefinitionValid());

                            if (bInitialLoopEndCondition && !bFinalLoopEndCondition)
                            {
                                --nThrowAwayValidLayoutLimit;
                            }
                        }

                        const bool bSplitError = !Split( nDeadLine, bTryToSplit, ( bTableRowKeep && !(bAllowSplitOfRow || !bEmulateTableKeepFwdMoveAllowed) ) );
                        if( !bTryToSplit && !bSplitError && nUnSplitted > 0 )
                        {
                            --nUnSplitted;
                        }

                        // #i29771# Two tries to split the table
                        // If an error occurred during splitting. We start a second
                        // try, this time without splitting of table rows.
                        if ( bSplitError )
                        {
                            if ( HasFollowFlowLine() )
                                RemoveFollowFlowLine();
                        }

                        // If splitting the table was successful or not,
                        // we do not want to have 'empty' follow tables.
                        if ( GetFollow() && !GetFollow()->GetFirstNonHeadlineRow() )
                            Join();

                        // We want to restore the situation before the failed
                        // split operation as good as possible. Therefore we
                        // do some more calculations. Note: Restricting this
                        // to nDeadLine may not be enough.
                        if ( bSplitError && bTryToSplit ) // no restart if we did not try to split: i72847, i79426
                        {
                            lcl_RecalcRow( static_cast<SwRowFrame*>(Lower()), LONG_MAX );
                            setFrameAreaPositionValid(false);
                            bTryToSplit = false;
                            continue;
                        }

                        bTryToSplit = !bSplitError;

                        //To avoid oscillations the Follow must become valid now
                        if ( GetFollow() )
                        {
                            // #i80924#
                            // After a successful split assure that the first row
                            // is invalid. When graphics are present, this isn't hold.
                            // Note: defect i80924 could also be fixed, if it is
                            // assured, that <SwLayNotify::bLowersComplete> is only
                            // set, if all lower are valid *and* are correct laid out.
                            if ( !bSplitError && GetFollow()->GetLower() )
                            {
                                GetFollow()->GetLower()->InvalidatePos();
                            }
                            SwRectFnSet fnRectX(GetFollow());

                            static sal_uInt8 nStack = 0;
                            if ( !StackHack::IsLocked() && nStack < 4 )
                            {
                                ++nStack;
                                StackHack aHack;
                                pAccess.reset();

                                GetFollow()->MakeAll(pRenderContext);

                                pAccess = o3tl::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
                                pAttrs = pAccess->Get();

                                GetFollow()->SetLowersFormatted(false);
                                // #i43913# - lock follow table
                                // to avoid its formatting during the format of
                                // its content.
                                const bool bOldJoinLock =  GetFollow()->IsJoinLocked();
                                GetFollow()->LockJoin();
                                ::lcl_RecalcRow( static_cast<SwRowFrame*>(GetFollow()->Lower()),
                                                 fnRectX.GetBottom(GetFollow()->GetUpper()->getFrameArea()) );
                                // #i43913#
                                // #i63632# Do not unlock the
                                // follow if it wasn't locked before.
                                if ( !bOldJoinLock )
                                    GetFollow()->UnlockJoin();

                                if ( !GetFollow()->GetFollow() )
                                {
                                    SwFrame* pNxt = static_cast<SwFrame*>(GetFollow())->FindNext();
                                    if ( pNxt )
                                    {
                                        // #i18103# - no formatting of found next
                                        // frame, if it's a follow section of the
                                        // 'ColLocked' section, the follow table is
                                        // in.
                                        bool bCalcNxt = true;
                                        if ( GetFollow()->IsInSct() && pNxt->IsSctFrame() )
                                        {
                                            SwSectionFrame* pSct = GetFollow()->FindSctFrame();
                                            if ( pSct->IsColLocked() &&
                                                 pSct->GetFollow() == pNxt )
                                            {
                                                bCalcNxt = false;
                                            }
                                        }
                                        if ( bCalcNxt )
                                        {
                                            pNxt->Calc(pRenderContext);
                                        }
                                    }
                                }
                                --nStack;
                            }
                            else if ( GetFollow() == GetNext() )
                                GetFollow()->MoveFwd( true, false );
                        }
                        continue;
                    }
                }
            }

            // Set to false again as early as possible.
            bLastRowHasToMoveToFollow = false;

            if( IsInSct() && bMovedFwd && bMakePage && GetUpper()->IsColBodyFrame() &&
                GetUpper()->GetUpper()->GetUpper()->IsSctFrame() &&
                ( GetUpper()->GetUpper()->GetPrev() || GetIndPrev() ) &&
                static_cast<SwSectionFrame*>(GetUpper()->GetUpper()->GetUpper())->MoveAllowed(this) )
            {
                bMovedFwd = false;
            }

            // #i29771# Reset bTryToSplit flag on change of upper
            const SwFrame* pOldUpper = GetUpper();

            //Let's see if we find some place anywhere...
            if ( !bMovedFwd && !MoveFwd( bMakePage, false ) )
                bMakePage = false;

            // #i29771# Reset bSplitError flag on change of upper
            if ( GetUpper() != pOldUpper )
            {
                bTryToSplit = true;
                nUnSplitted = 5;
            }

            aRectFnSet.Refresh(this);
            m_bCalcLowers = true;
            bMovedFwd = true;
            aNotify.SetLowersComplete( false );
            if ( IsFollow() )
            {
                //To avoid oscillations now invalid master should drop behind.
                SwTabFrame *pTab = FindMaster();
                if ( pTab->GetUpper() )
                    pTab->GetUpper()->Calc(pRenderContext);
                pTab->Calc(pRenderContext);
                pTab->SetLowersFormatted( false );
            }

            //If my neighbour is my Follow at the same time, I'll swallow it up.
            if ( ( GetNext() && GetNext() == GetFollow() ) || !GetLower() )
            {
                if ( HasFollowFlowLine() )
                    RemoveFollowFlowLine();
                if ( GetFollow() )
                    Join();
            }

            if ( bMovedBwd && GetUpper() )
            {
                //During floating back the upper was animated to do a full repaint,
                //we can now skip this after the whole back and forth floating.
                GetUpper()->ResetCompletePaint();
            }

            if (m_bCalcLowers && isFrameAreaDefinitionValid())
            {
                // #i44910# - format of lower frames unnecessary
                // and can cause layout loops, if table doesn't fit and isn't
                // allowed to split.
                SwTwips nDistToUpperPrtBottom =
                    aRectFnSet.BottomDist( getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()));
                if ( nDistToUpperPrtBottom >= 0 || bTryToSplit )
                {
                    lcl_RecalcTable( *this, nullptr, aNotify );
                    m_bLowersFormatted = true;
                    m_bCalcLowers = false;
                    if (!isFramePrintAreaValid())
                        m_pTable->SetRowsToRepeat(1);
                }
    #if OSL_DEBUG_LEVEL > 0
                else
                {
                    OSL_FAIL( "debug assertion: <SwTabFrame::MakeAll()> - format of table lowers suppressed by fix i44910" );
                }
    #endif
            }

        } //while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )

        //If my direct predecessor is my master now, it can destroy me during the
        //next best opportunity.
        if ( IsFollow() )
        {
            SwFrame *pPre = GetPrev();
            if ( pPre && pPre->IsTabFrame() && static_cast<SwTabFrame*>(pPre)->GetFollow() == this)
                pPre->InvalidatePos();
        }

        m_bCalcLowers = m_bONECalcLowers = false;
        pAccess.reset();
        UnlockJoin();
        if ( bMovedFwd || bMovedBwd || !bOldValidPos )
            aNotify.SetInvaKeep();
    }

    /// Calculate the offsets arising because of FlyFrames
    bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper,
                                   long& rLeftOffset,
                                   long& rRightOffset ) const
    {
        bool bInvalidatePrtArea = false;
        const SwPageFrame *pPage = FindPageFrame();
        const SwFlyFrame* pMyFly = FindFlyFrame();

        // --> #108724# Page header/footer content doesn't have to wrap around
        //              floating screen objects

        const IDocumentSettingAccess& rIDSA = GetFormat()->getIDocumentSettingAccess();
        const bool bWrapAllowed = rIDSA.get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING) ||
                                    ( !IsInFootnote() && nullptr == FindFooterOrHeader() );

        if ( pPage->GetSortedObjs() && bWrapAllowed )
        {
            SwRectFnSet aRectFnSet(this);
            const bool bConsiderWrapOnObjPos = rIDSA.get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION);
            long nPrtPos = aRectFnSet.GetTop(getFrameArea());
            nPrtPos = aRectFnSet.YInc( nPrtPos, rUpper );
            SwRect aRect( getFrameArea() );
            long nYDiff = aRectFnSet.YDiff( aRectFnSet.GetTop(getFramePrintArea()), rUpper );
            if( nYDiff > 0 )
                aRectFnSet.AddBottom( aRect, -nYDiff );
            for ( size_t i = 0; i < pPage->GetSortedObjs()->size(); ++i )
            {
                SwAnchoredObject* pAnchoredObj = (*pPage->GetSortedObjs())[i];
                if ( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) !=  nullptr )
                {
                    SwFlyFrame *pFly = static_cast<SwFlyFrame*>(pAnchoredObj);
                    const SwRect aFlyRect = pFly->GetObjRectWithSpaces();
                    // #i26945# - correction of conditions,
                    // if Writer fly frame has to be considered:
                    // - no need to check, if top of Writer fly frame differs
                    //   from FAR_AWAY, because it's also checked, if the Writer
                    //   fly frame rectangle overlaps with <aRect>
                    // - no check, if bottom of anchor frame is prior the top of
                    //   the table, because Writer fly frames can be negative positioned.
                    // - correct check, if the Writer fly frame is an lower of the
                    //   table, because table lines/rows can split and a at-character
                    //   anchored Writer fly frame could be positioned in the follow
                    //   flow line.
                    // - add condition, that an existing anchor character text frame
                    //   has to be on the same page as the table.
                    //   E.g., it could happen, that the fly frame is still registered
                    //   at the page frame, the table is on, but it's anchor character
                    //   text frame has already changed its page.
                    const SwTextFrame* pAnchorCharFrame = pFly->FindAnchorCharFrame();
                    bool bConsiderFly =
                        // #i46807# - do not consider invalid
                        // Writer fly frames.
                        pFly->isFrameAreaDefinitionValid() &&
                        // fly anchored at character
                        pFly->IsFlyAtContentFrame() &&
                        // fly overlaps with corresponding table rectangle
                        aFlyRect.IsOver( aRect ) &&
                        // fly isn't lower of table and
                        // anchor character frame of fly isn't lower of table
                        ( !IsAnLower( pFly ) &&
                          ( !pAnchorCharFrame || !IsAnLower( pAnchorCharFrame ) ) ) &&
                        // table isn't lower of fly
                        !pFly->IsAnLower( this ) &&
                        // fly is lower of fly, the table is in
                        // #123274# - correction
                        // assure that fly isn't a lower of a fly, the table isn't in.
                        // E.g., a table in the body doesn't wrap around a graphic,
                        // which is inside a frame.
                        ( ( !pMyFly ||
                            pMyFly->IsAnLower( pFly ) ) &&
                          pMyFly == pFly->GetAnchorFrameContainingAnchPos()->FindFlyFrame() ) &&
                        // anchor frame not on following page
                        pPage->GetPhyPageNum() >=
                          pFly->GetAnchorFrame()->FindPageFrame()->GetPhyPageNum() &&
                        // anchor character text frame on same page
                        ( !pAnchorCharFrame ||
                          pAnchorCharFrame->FindPageFrame()->GetPhyPageNum() ==
                            pPage->GetPhyPageNum() );

                    if ( bConsiderFly )
                    {
                        const SwFrame* pFlyHeaderFooterFrame = pFly->GetAnchorFrame()->FindFooterOrHeader();
                        const SwFrame* pThisHeaderFooterFrame = FindFooterOrHeader();

                        if ( pFlyHeaderFooterFrame != pThisHeaderFooterFrame &&
                            // #148493# If bConsiderWrapOnObjPos is set,
                            // we want to consider the fly if it is located in the header and
                            // the table is located in the body:
                             ( !bConsiderWrapOnObjPos || nullptr != pThisHeaderFooterFrame || !pFlyHeaderFooterFrame->IsHeaderFrame() ) )
                            bConsiderFly = false;
                    }

                    if ( bConsiderFly )
                    {
                        const SwFormatSurround   &rSur = pFly->GetFormat()->GetSurround();
                        const SwFormatHoriOrient &rHori= pFly->GetFormat()->GetHoriOrient();
                        if ( css::text::WrapTextMode_NONE == rSur.GetSurround() )
                        {
                            long nBottom = aRectFnSet.GetBottom(aFlyRect);
                            if( aRectFnSet.YDiff( nPrtPos, nBottom ) < 0 )
                                nPrtPos = nBottom;
                            bInvalidatePrtArea = true;
                        }
                        if ( (css::text::WrapTextMode_RIGHT    == rSur.GetSurround() ||
                              css::text::WrapTextMode_PARALLEL == rSur.GetSurround())&&
                             text::HoriOrientation::LEFT == rHori.GetHoriOrient() )
                        {
                            const long nWidth = aRectFnSet.XDiff(
                                aRectFnSet.GetRight(aFlyRect),
                                aRectFnSet.GetLeft(pFly->GetAnchorFrame()->getFrameArea()) );
                            rLeftOffset = std::max( rLeftOffset, nWidth );
                            bInvalidatePrtArea = true;
                        }
                        if ( (css::text::WrapTextMode_LEFT     == rSur.GetSurround() ||
                              css::text::WrapTextMode_PARALLEL == rSur.GetSurround())&&
                             text::HoriOrientation::RIGHT == rHori.GetHoriOrient() )
                        {
                            const long nWidth = aRectFnSet.XDiff(
                                aRectFnSet.GetRight(pFly->GetAnchorFrame()->getFrameArea()),
                                aRectFnSet.GetLeft(aFlyRect) );
                            rRightOffset = std::max( rRightOffset, nWidth );
                            bInvalidatePrtArea = true;
                        }
                    }
                }
            }
            rUpper = aRectFnSet.YDiff( nPrtPos, aRectFnSet.GetTop(getFrameArea()) );
        }

        return bInvalidatePrtArea;
    }

    /// "Formats" the frame; Frame and PrtArea.
    /// The fixed size is not adjusted here.
    void SwTabFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs *pAttrs )
    {
        OSL_ENSURE( pAttrs, "TabFrame::Format, pAttrs is 0." );

        SwRectFnSet aRectFnSet(this);
        if ( !isFrameAreaSizeValid() )
        {
            long nDiff = aRectFnSet.GetWidth(GetUpper()->getFramePrintArea()) -
                         aRectFnSet.GetWidth(getFrameArea());
            if( nDiff )
            {
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                aRectFnSet.AddRight( aFrm, nDiff );
            }
        }

        //VarSize is always the height.
        //For the upper/lower border the same rules apply as for cntfrms (see
        //MakePrtArea() of those).

        SwTwips nUpper = CalcUpperSpace( pAttrs );

        //We want to dodge the border. Two possibilities:
        //1. There are borders with SurroundNone, dodge them completely
        //2. There are borders which only float on the right or the left side and
        //   are right or left aligned, those set the minimum for the borders.
        long nTmpRight = -1000000,
             nLeftOffset  = 0;
        if( CalcFlyOffsets( nUpper, nLeftOffset, nTmpRight ) )
        {
            setFramePrintAreaValid(false);
        }

        long nRightOffset = std::max( 0L, nTmpRight );

        SwTwips nLower = pAttrs->CalcBottomLine();
        // #i29550#
        if ( IsCollapsingBorders() )
            nLower += GetBottomLineSize();

        if ( !isFramePrintAreaValid() )
        {
            setFramePrintAreaValid(true);

            //The width of the PrtArea is given by the FrameFormat, the borders have to
            //be set accordingly.
            //Minimum borders are determined depending on margins and shadows.
            //The borders are adjusted so that the PrtArea is aligned into the Frame
            //according to the adjustment.
            //If the adjustment is 0, the borders are set according to the border
            //attributes.

            const SwTwips nOldHeight = aRectFnSet.GetHeight(getFramePrintArea());
            const SwTwips nMax = aRectFnSet.GetWidth(getFrameArea());

            // OD 14.03.2003 #i9040# - adjust variable names.
            const SwTwips nLeftLine  = pAttrs->CalcLeftLine();
            const SwTwips nRightLine = pAttrs->CalcRightLine();

            //The width possibly is a percentage value. If the table is inside
            //something else, the value applies to the surrounding. If it's the body
            //the value applies to the screen width in the BrowseView.
            const SwFormatFrameSize &rSz = GetFormat()->GetFrameSize();
            // OD 14.03.2003 #i9040# - adjust variable name.
            const SwTwips nWishedTableWidth = CalcRel( rSz );

            bool bCheckBrowseWidth = false;

            // OD 14.03.2003 #i9040# - insert new variables for left/right spacing.
            SwTwips nLeftSpacing  = 0;
            SwTwips nRightSpacing = 0;
            switch ( GetFormat()->GetHoriOrient().GetHoriOrient() )
            {
                case text::HoriOrientation::LEFT:
                    {
                        // left indent:
                        nLeftSpacing = nLeftLine + nLeftOffset;
                        // OD 06.03.2003 #i9040# - correct calculation of right indent:
                        // - Consider right indent given by right line attributes.
                        // - Consider negative right indent.
                        // wished right indent determined by wished table width and
                        // left offset given by surround fly frames on the left:
                        const SwTwips nWishRight = nMax - nWishedTableWidth - nLeftOffset;
                        if ( nRightOffset > 0 )
                        {
                            // surrounding fly frames on the right
                            // -> right indent is maximum of given right offset
                            //    and wished right offset.
                            nRightSpacing = nRightLine + std::max( nRightOffset, nWishRight );
                        }
                        else
                        {
                            // no surrounding fly frames on the right
                            // If intrinsic right indent (intrinsic means not considering
                            // determined left indent) is negative,
                            //      then hold this intrinsic indent,
                            //      otherwise non negative wished right indent is hold.
                            nRightSpacing = nRightLine +
                                            ( ( (nWishRight+nLeftOffset) < 0 ) ?
                                                (nWishRight+nLeftOffset) :
                                                std::max( 0L, nWishRight ) );
                        }
                    }
                    break;
                case text::HoriOrientation::RIGHT:
                    {
                        // right indent:
                        nRightSpacing = nRightLine + nRightOffset;
                        // OD 06.03.2003 #i9040# - correct calculation of left indent:
                        // - Consider left indent given by left line attributes.
                        // - Consider negative left indent.
                        // wished left indent determined by wished table width and
                        // right offset given by surrounding fly frames on the right:
                        const SwTwips nWishLeft = nMax - nWishedTableWidth - nRightOffset;
                        if ( nLeftOffset > 0 )
                        {
                            // surrounding fly frames on the left
                            // -> right indent is maximum of given left offset
                            //    and wished left offset.
                            nLeftSpacing = nLeftLine + std::max( nLeftOffset, nWishLeft );
                        }
                        else
                        {
                            // no surrounding fly frames on the left
                            // If intrinsic left indent (intrinsic = not considering
                            // determined right indent) is negative,
                            //      then hold this intrinsic indent,
                            //      otherwise non negative wished left indent is hold.
                            nLeftSpacing = nLeftLine +
                                           ( ( (nWishLeft+nRightOffset) < 0 ) ?
                                               (nWishLeft+nRightOffset) :
                                               std::max( 0L, nWishLeft ) );
                        }
                    }
                    break;
                case text::HoriOrientation::CENTER:
                    {
                        // OD 07.03.2003 #i9040# - consider left/right line attribute.
                        // OD 10.03.2003 #i9040# -
                        const SwTwips nCenterSpacing = ( nMax - nWishedTableWidth ) / 2;
                        nLeftSpacing = nLeftLine +
                                       ( (nLeftOffset > 0) ?
                                         std::max( nCenterSpacing, nLeftOffset ) :
                                         nCenterSpacing );
                        nRightSpacing = nRightLine +
                                        ( (nRightOffset > 0) ?
                                          std::max( nCenterSpacing, nRightOffset ) :
                                          nCenterSpacing );
                    }
                    break;
                case text::HoriOrientation::FULL:
                        //This things grows over the whole width.
                        //Only the free space needed for the border is taken into
                        //account. The attribute values of LRSpace are ignored
                        //intentionally.
                        bCheckBrowseWidth = true;
                        nLeftSpacing  = nLeftLine + nLeftOffset;
                        nRightSpacing = nRightLine + nRightOffset;
                    break;
                case text::HoriOrientation::NONE:
                    {
                        //The border are defined by the border attribute.
                        nLeftSpacing = pAttrs->CalcLeft( this );
                        if( nLeftOffset )
                        {
                            // OD 07.03.2003 #i9040# - surround fly frames only, if
                            // they overlap with the table.
                            // Thus, take maximum of left spacing and left offset.
                            // OD 10.03.2003 #i9040# - consider left line attribute.
                            nLeftSpacing = std::max( nLeftSpacing, ( nLeftOffset + nLeftLine ) );
                        }
                        // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
                        nRightSpacing = pAttrs->CalcRight( this );
                        if( nRightOffset )
                        {
                            // OD 07.03.2003 #i9040# - surround fly frames only, if
                            // they overlap with the table.
                            // Thus, take maximum of right spacing and right offset.
                            // OD 10.03.2003 #i9040# - consider right line attribute.
                            nRightSpacing = std::max( nRightSpacing, ( nRightOffset + nRightLine ) );
                        }
                    }
                    break;
                case text::HoriOrientation::LEFT_AND_WIDTH:
                    {
                        // count left border and width (Word specialty)
                        // OD 10.03.2003 #i9040# - no width alignment in online mode.
                        //bCheckBrowseWidth = true;
                        nLeftSpacing = pAttrs->CalcLeft( this );
                        if( nLeftOffset )
                        {
                            // OD 10.03.2003 #i9040# - surround fly frames only, if
                            // they overlap with the table.
                            // Thus, take maximum of right spacing and right offset.
                            // OD 10.03.2003 #i9040# - consider left line attribute.
                            nLeftSpacing = std::max( nLeftSpacing, ( pAttrs->CalcLeftLine() + nLeftOffset ) );
                        }
                        // OD 10.03.2003 #i9040# - consider right and left line attribute.
                        const SwTwips nWishRight =
                                nMax - (nLeftSpacing-pAttrs->CalcLeftLine()) - nWishedTableWidth;
                        nRightSpacing = nRightLine +
                                        ( (nRightOffset > 0) ?
                                          std::max( nWishRight, nRightOffset ) :
                                          nWishRight );
                    }
                    break;
                default:
                    OSL_FAIL( "Invalid orientation for table." );
            }

            // #i26250# - extend bottom printing area, if table
            // is last content inside a table cell.
            if ( GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS) &&
                 GetUpper()->IsInTab() && !GetIndNext() )
            {
                nLower += pAttrs->GetULSpace().GetLower();
            }
            aRectFnSet.SetYMargins( *this, nUpper, nLower );
            if( (nMax - MINLAY) < (nLeftSpacing + nRightSpacing) )
                aRectFnSet.SetXMargins( *this, 0, 0 );
            else
                aRectFnSet.SetXMargins( *this, nLeftSpacing, nRightSpacing );

            SwViewShell *pSh = getRootFrame()->GetCurrShell();
            if ( bCheckBrowseWidth &&
                 pSh && pSh->GetViewOptions()->getBrowseMode() &&
                 GetUpper()->IsPageBodyFrame() &&  // only PageBodyFrames and not ColBodyFrames
                 pSh->VisArea().Width() )
            {
                //Don't overlap the edge of the visible area.
                //The page width can be bigger because objects with
                //"over-size" are possible (RootFrame::ImplCalcBrowseWidth())
                long nWidth = pSh->GetBrowseWidth();
                nWidth -= getFramePrintArea().Left();
                nWidth -= pAttrs->CalcRightLine();

                SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
                aPrt.Width( std::min( nWidth, aPrt.Width() ) );
            }

            if ( nOldHeight != aRectFnSet.GetHeight(getFramePrintArea()) )
            {
                setFrameAreaSizeValid(false);
            }
        }

        if ( !isFrameAreaSizeValid() )
        {
            setFrameAreaSizeValid(true);

            //The size is defined by the content plus the borders.
            SwTwips nRemaining = 0, nDiff;
            SwFrame *pFrame = m_pLower;
            while ( pFrame )
            {
                nRemaining += aRectFnSet.GetHeight(pFrame->getFrameArea());
                pFrame = pFrame->GetNext();
            }
            //And now add the borders
            nRemaining += nUpper + nLower;

            nDiff = aRectFnSet.GetHeight(getFrameArea()) - nRemaining;
            if ( nDiff > 0 )
                Shrink( nDiff );
            else if ( nDiff < 0 )
                Grow( -nDiff );
        }
    }

    SwTwips SwTabFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo )
    {
        SwRectFnSet aRectFnSet(this);
        SwTwips nHeight = aRectFnSet.GetHeight(getFrameArea());
        if( nHeight > 0 && nDist > ( LONG_MAX - nHeight ) )
            nDist = LONG_MAX - nHeight;

        if ( bTst && !IsRestrictTableGrowth() )
            return nDist;

        if ( GetUpper() )
        {
            SwRect aOldFrame( getFrameArea() );

            //The upper only grows as far as needed. nReal provides the distance
            //which is already available.
            SwTwips nReal = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea());
            SwFrame *pFrame = GetUpper()->Lower();
            while ( pFrame && GetFollow() != pFrame )
            {
                nReal -= aRectFnSet.GetHeight(pFrame->getFrameArea());
                pFrame = pFrame->GetNext();
            }

            if ( nReal < nDist )
            {
                long nTmp = GetUpper()->Grow( nDist - std::max<long>(nReal, 0), bTst, bInfo );

                if ( IsRestrictTableGrowth() )
                {
                    nTmp = std::min( nDist, nReal + nTmp );
                    nDist = nTmp < 0 ? 0 : nTmp;
                }
            }

            if ( !bTst )
            {
                {
                    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                    aRectFnSet.AddBottom( aFrm, nDist );
                }

                SwRootFrame *pRootFrame = getRootFrame();
                if( pRootFrame && pRootFrame->IsAnyShellAccessible() &&
                    pRootFrame->GetCurrShell() )
                {
                    pRootFrame->GetCurrShell()->Imp()->MoveAccessibleFrame( this, aOldFrame );
                }
            }
        }

        if ( !bTst && ( nDist || IsRestrictTableGrowth() ) )
        {
            SwPageFrame *pPage = FindPageFrame();
            if ( GetNext() )
            {
                GetNext()->InvalidatePos_();
                if ( GetNext()->IsContentFrame() )
                    GetNext()->InvalidatePage( pPage );
            }
            // #i28701# - Due to the new object positioning the
            // frame on the next page/column can flow backward (e.g. it was moved
            // forward due to the positioning of its objects ). Thus, invalivate this
            // next frame, if document compatibility option 'Consider wrapping style
            // influence on object positioning' is ON.
            else if ( GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) )
            {
                InvalidateNextPos();
            }
            InvalidateAll_();
            InvalidatePage( pPage );
            SetComplete();

            SvxBrushItem aBack = GetFormat()->makeBackgroundBrushItem();
            const SvxGraphicPosition ePos = aBack.GetGraphicPos();
            if ( GPOS_NONE != ePos && GPOS_TILED != ePos )
                SetCompletePaint();
        }

        return nDist;
    }

    void SwTabFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew )
    {
        sal_uInt8 nInvFlags = 0;
        bool bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which();

        if( bAttrSetChg )
        {
            SfxItemIter aNIter( *static_cast<const SwAttrSetChg*>(pNew)->GetChgSet() );
            SfxItemIter aOIter( *static_cast<const SwAttrSetChg*>(pOld)->GetChgSet() );
            SwAttrSetChg aOldSet( *static_cast<const SwAttrSetChg*>(pOld) );
            SwAttrSetChg aNewSet( *static_cast<const SwAttrSetChg*>(pNew) );
            while( true )
            {
                UpdateAttr_( aOIter.GetCurItem(),
                             aNIter.GetCurItem(), nInvFlags,
                             &aOldSet, &aNewSet );
                if( aNIter.IsAtEnd() )
                    break;
                aNIter.NextItem();
                aOIter.NextItem();
            }
            if ( aOldSet.Count() || aNewSet.Count() )
                SwLayoutFrame::Modify( &aOldSet, &aNewSet );
        }
        else
            UpdateAttr_( pOld, pNew, nInvFlags );

        if ( nInvFlags != 0 )
        {
            SwPageFrame *pPage = FindPageFrame();
            InvalidatePage( pPage );
            if ( nInvFlags & 0x02 )
                InvalidatePrt_();
            if ( nInvFlags & 0x40 )
                InvalidatePos_();
            SwFrame *pTmp;
            if ( nullptr != (pTmp = GetIndNext()) )
            {
                if ( nInvFlags & 0x04 )
                {
                    pTmp->InvalidatePrt_();
                    if ( pTmp->IsContentFrame() )
                        pTmp->InvalidatePage( pPage );
                }
                if ( nInvFlags & 0x10 )
                    pTmp->SetCompletePaint();
            }
            if ( nInvFlags & 0x08 && nullptr != (pTmp = GetPrev()) )
            {
                pTmp->InvalidatePrt_();
                if ( pTmp->IsContentFrame() )
                    pTmp->InvalidatePage( pPage );
            }
            if ( nInvFlags & 0x20  )
            {
                if ( pPage && pPage->GetUpper() && !IsFollow() )
                    static_cast<SwRootFrame*>(pPage->GetUpper())->InvalidateBrowseWidth();
            }
            if ( nInvFlags & 0x80 )
                InvalidateNextPos();
        }
    }

    void SwTabFrame::UpdateAttr_( const SfxPoolItem *pOld, const SfxPoolItem *pNew,
                                sal_uInt8 &rInvFlags,
                                SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet )
    {
        bool bClear = true;
        const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
        switch( nWhich )
        {
            case RES_TBLHEADLINECHG:
                if ( IsFollow() )
                {
                    // Delete remaining headlines:
                    SwRowFrame* pLowerRow = nullptr;
                    while ( nullptr != ( pLowerRow = static_cast<SwRowFrame*>(Lower()) ) && pLowerRow->IsRepeatedHeadline() )
                    {
                        pLowerRow->Cut();
                        SwFrame::DestroyFrame(pLowerRow);
                    }

                    // insert new headlines
                    const sal_uInt16 nNewRepeat = GetTable()->GetRowsToRepeat();
                    for ( sal_uInt16 nIdx = 0; nIdx < nNewRepeat; ++nIdx )
                    {
                        bDontCreateObjects = true;          //frmtool
                        SwRowFrame* pHeadline = new SwRowFrame( *GetTable()->GetTabLines()[ nIdx ], this );
                        pHeadline->SetRepeatedHeadline( true );
                        bDontCreateObjects = false;
                        pHeadline->Paste( this, pLowerRow );
                    }
                }
                rInvFlags |= 0x02;
                break;

            case RES_FRM_SIZE:
            case RES_HORI_ORIENT:
                rInvFlags |= 0x22;
                break;

            case RES_PAGEDESC:                      //Attribute changes (on/off)
                if ( IsInDocBody() )
                {
                    rInvFlags |= 0x40;
                    SwPageFrame *pPage = FindPageFrame();
                    if (pPage)
                    {
                        if ( !GetPrev() )
                            CheckPageDescs( pPage );
                        if (GetFormat()->GetPageDesc().GetNumOffset())
                            static_cast<SwRootFrame*>(pPage->GetUpper())->SetVirtPageNum( true );
                        SwDocPosUpdate aMsgHint( pPage->getFrameArea().Top() );
                        GetFormat()->GetDoc()->getIDocumentFieldsAccess().UpdatePageFields( &aMsgHint );
                    }
                }
                break;

            case RES_BREAK:
                rInvFlags |= 0xC0;
                break;

            case RES_LAYOUT_SPLIT:
                if ( !IsFollow() )
                    rInvFlags |= 0x40;
                break;
            case RES_FRAMEDIR :
                SetDerivedR2L( false );
                CheckDirChange();
                break;
            case RES_COLLAPSING_BORDERS :
                rInvFlags |= 0x02;
                lcl_InvalidateAllLowersPrt( this );
                break;
            case RES_UL_SPACE:
                rInvFlags |= 0x1C;
                SAL_FALLTHROUGH;

            default:
                bClear = false;
        }
        if ( bClear )
        {
            if ( pOldSet || pNewSet )
            {
                if ( pOldSet )
                    pOldSet->ClearItem( nWhich );
                if ( pNewSet )
                    pNewSet->ClearItem( nWhich );
            }
            else
                SwLayoutFrame::Modify( pOld, pNew );
        }
    }

    bool SwTabFrame::GetInfo( SfxPoolItem &rHint ) const
    {
        if ( RES_VIRTPAGENUM_INFO == rHint.Which() && IsInDocBody() && !IsFollow() )
        {
            SwVirtPageNumInfo &rInfo = static_cast<SwVirtPageNumInfo&>(rHint);
            const SwPageFrame *pPage = FindPageFrame();
            if ( pPage  )
            {
                if ( pPage == rInfo.GetOrigPage() && !GetPrev() )
                {
                    //Here it should be (can temporary be different, should we be
                    //                    concerned about this?)
                    rInfo.SetInfo( pPage, this );
                    return false;
                }
                if ( pPage->GetPhyPageNum() < rInfo.GetOrigPage()->GetPhyPageNum() &&
                     (!rInfo.GetPage() || pPage->GetPhyPageNum() > rInfo.GetPage()->GetPhyPageNum()))
                {
                    //This could be the one.
                    rInfo.SetInfo( pPage, this );
                }
            }
        }
        return true;
    }

    SwContentFrame *SwTabFrame::FindLastContent()
    {
        SwFrame *pRet = m_pLower;

        while ( pRet && !pRet->IsContentFrame() )
        {
            SwFrame *pOld = pRet;

            SwFrame *pTmp = pRet;             // To skip empty section frames
            while ( pRet->GetNext() )
            {
                pRet = pRet->GetNext();
                if( !pRet->IsSctFrame() || static_cast<SwSectionFrame*>(pRet)->GetSection() )
                    pTmp = pRet;
            }
            pRet = pTmp;

            if ( pRet->GetLower() )
                pRet = pRet->GetLower();
            if ( pRet == pOld )
            {
                // Check all other columns if there is a column based section with
                // an empty last column at the end of the last line - this is done
                // by SwSectionFrame::FindLastContent
                if( pRet->IsColBodyFrame() )
                {
    #if OSL_DEBUG_LEVEL > 0
                    SwSectionFrame* pSect = pRet->FindSctFrame();
                    OSL_ENSURE( pSect, "Where does this column come from?");
                    OSL_ENSURE( IsAnLower( pSect ), "Splitted cell?" );
    #endif
                    return pRet->FindSctFrame()->FindLastContent();
                }

                // pRet may be a cell frame without a lower (cell has been split).
                // We have to find the last content the hard way:

                OSL_ENSURE( pRet->IsCellFrame(), "SwTabFrame::FindLastContent failed" );
                const SwFrame* pRow = pRet->GetUpper();
                while ( pRow && !pRow->GetUpper()->IsTabFrame() )
                    pRow = pRow->GetUpper();
                const SwContentFrame* pContentFrame = pRow ? static_cast<const SwLayoutFrame*>(pRow)->ContainsContent() : nullptr;
                pRet = nullptr;

                while ( pContentFrame && static_cast<const SwLayoutFrame*>(pRow)->IsAnLower( pContentFrame ) )
                {
                    pRet = const_cast<SwContentFrame*>(pContentFrame);
                    pContentFrame = pContentFrame->GetNextContentFrame();
                }
            }
        }

        // #112929# There actually is a situation, which results in pRet = 0:
        // Insert frame, insert table via text <-> table. This gives you a frame
        // containing a table without any other content frames. Split the table
        // and undo the splitting. This operation gives us a table frame without
        // a lower.
        if ( pRet )
        {
            while ( pRet->GetNext() )
                pRet = pRet->GetNext();

            if( pRet->IsSctFrame() )
                pRet = static_cast<SwSectionFrame*>(pRet)->FindLastContent();
        }

        return static_cast<SwContentFrame*>(pRet);
    }

    /// Return value defines if the frm needs to be relocated
    bool SwTabFrame::ShouldBwdMoved( SwLayoutFrame *pNewUpper, bool, bool &rReformat )
    {
        rReformat = false;
        if ( SwFlowFrame::IsMoveBwdJump() || !IsPrevObjMove() )
        {
            //Floating back Frame's is quite time consuming unfortunately.
            //Most often the location where the Frame wants to float to has the same
            //FixSize as the Frame itself. In such a situation it's easy to check if
            //the Frame will find enough space for its VarSize, if this is not the
            //case, the relocation can be skipped.
            //Checking if the Frame will find enough space is done by the Frame itself,
            //this also takes the possibility of splitting the Frame into account.
            //If the FixSize is different or Flys are involved  (at the old or the
            //new position) the whole checks don't make sense at all, the Frame then
            //needs to be relocated tentatively (if a bit of space is available).

            //The FixSize of the surrounding which contain tables is always the
            //width.

            SwPageFrame *pOldPage = FindPageFrame(),
                      *pNewPage = pNewUpper->FindPageFrame();
            bool bMoveAnyway = false;
            SwTwips nSpace = 0;

            SwRectFnSet aRectFnSet(this);
            if ( !SwFlowFrame::IsMoveBwdJump() )
            {

                long nOldWidth = aRectFnSet.GetWidth(GetUpper()->getFramePrintArea());
                SwRectFnSet fnRectX(pNewUpper);
                long nNewWidth = fnRectX.GetWidth(pNewUpper->getFramePrintArea());
                if( std::abs( nNewWidth - nOldWidth ) < 2 )
                {
                    bMoveAnyway = BwdMoveNecessary( pOldPage, getFrameArea() ) > 1;
                    if( !bMoveAnyway )
                    {
                        SwRect aRect( pNewUpper->getFramePrintArea() );
                        aRect.Pos() += pNewUpper->getFrameArea().Pos();
                        const SwFrame *pPrevFrame = pNewUpper->Lower();
                        while ( pPrevFrame && pPrevFrame != this )
                        {
                            fnRectX.SetTop( aRect, fnRectX.GetBottom(pPrevFrame->getFrameArea()) );
                            pPrevFrame = pPrevFrame->GetNext();
                        }
                        bMoveAnyway = BwdMoveNecessary( pNewPage, aRect) > 1;

                        // #i54861# Due to changes made in PrepareMake,
                        // the tabfrm may not have a correct position. Therefore
                        // it is possible that pNewUpper->getFramePrintArea().Height == 0. In this
                        // case the above calculation of nSpace might give wrong
                        // results and we really do not want to MoveBackward into a
                        // 0 height frame. If nTmpSpace is already <= 0, we take this
                        // value:
                        const SwTwips nTmpSpace = fnRectX.GetHeight(aRect);
                        if ( fnRectX.GetHeight(pNewUpper->getFramePrintArea()) > 0 || nTmpSpace <= 0 )
                            nSpace = nTmpSpace;

                        const SwViewShell *pSh = getRootFrame()->GetCurrShell();
                        if( pSh && pSh->GetViewOptions()->getBrowseMode() )
                            nSpace += pNewUpper->Grow( LONG_MAX, true );
                    }
                }
                else if (!m_bLockBackMove)
                    bMoveAnyway = true;
            }
            else if (!m_bLockBackMove)
                bMoveAnyway = true;

            if ( bMoveAnyway )
            {
                rReformat = true;
                return true;
            }
            bool bFits = nSpace > 0;
            if (!bFits && aRectFnSet.GetHeight(getFrameArea()) == 0)
                // This frame fits into pNewUpper in case it has no space, but this
                // frame is empty.
                bFits = nSpace >= 0;
            if (!m_bLockBackMove && bFits)
            {
                // #i26945# - check, if follow flow line
                // contains frame, which are moved forward due to its object
                // positioning.
                SwRowFrame* pFirstRow = GetFirstNonHeadlineRow();
                if ( pFirstRow && pFirstRow->IsInFollowFlowRow() &&
                     SwLayouter::DoesRowContainMovedFwdFrame(
                                                *(pFirstRow->GetFormat()->GetDoc()),
                                                *pFirstRow ) )
                {
                    return false;
                }
                SwTwips nTmpHeight = CalcHeightOfFirstContentLine();

                // For some mysterious reason, I changed the good old
                // 'return nHeight <= nSpace' to 'return nTmpHeight < nSpace'.
                // This obviously results in problems with table frames in
                // sections. Remember: Every twip is sacred.
                return nTmpHeight <= nSpace;
            }
        }
        return false;
    }

    void SwTabFrame::Cut()
    {
        OSL_ENSURE( GetUpper(), "Cut without Upper()." );

        SwPageFrame *pPage = FindPageFrame();
        InvalidatePage( pPage );
        SwFrame *pFrame = GetNext();
        if( pFrame )
        {
            //The old follower eventually calculated a margin to the predecessor
            //which is obsolete now as it became the first one
            pFrame->InvalidatePrt_();
            pFrame->InvalidatePos_();
            if ( pFrame->IsContentFrame() )
                pFrame->InvalidatePage( pPage );
            if( IsInSct() && !GetPrev() )
            {
                SwSectionFrame* pSct = FindSctFrame();
                if( !pSct->IsFollow() )
                {
                    pSct->InvalidatePrt_();
                    pSct->InvalidatePage( pPage );
                }
            }
        }
        else
        {
            InvalidateNextPos();
            //Someone has to do the retouch: predecessor or upper
            if ( nullptr != (pFrame = GetPrev()) )
            {   pFrame->SetRetouche();
                pFrame->Prepare( PREP_WIDOWS_ORPHANS );
                pFrame->InvalidatePos_();
                if ( pFrame->IsContentFrame() )
                    pFrame->InvalidatePage( pPage );
            }
            //If I am (was) the only FlowFrame in my own upper, it has to do
            //the retouch. Moreover it has to do the retouch.
            else
            {   SwRootFrame *pRoot = static_cast<SwRootFrame*>(pPage->GetUpper());
                pRoot->SetSuperfluous();
                GetUpper()->SetCompletePaint();
                if( IsInSct() )
                {
                    SwSectionFrame* pSct = FindSctFrame();
                    if( !pSct->IsFollow() )
                    {
                        pSct->InvalidatePrt_();
                        pSct->InvalidatePage( pPage );
                    }
                }
            }
        }

        //First remove, then shrink the upper.
        SwLayoutFrame *pUp = GetUpper();
        SwRectFnSet aRectFnSet(this);
        RemoveFromLayout();
        if ( pUp )
        {
            OSL_ENSURE( !pUp->IsFootnoteFrame(), "Table in Footnote." );
            SwSectionFrame *pSct = nullptr;
            // #126020# - adjust check for empty section
            // #130797# - correct fix #126020#
            if ( !pUp->Lower() && pUp->IsInSct() &&
                 !(pSct = pUp->FindSctFrame())->ContainsContent() &&
                 !pSct->ContainsAny( true ) )
            {
                if ( pUp->GetUpper() )
                {
                    pSct->DelEmpty( false );
                    pSct->InvalidateSize_();
                }
            }
            // table-in-footnote: delete empty footnote frames (like SwContentFrame::Cut)
            else if (!pUp->Lower() && pUp->IsFootnoteFrame() && !pUp->IsColLocked())
            {
                if (pUp->GetNext() && !pUp->GetPrev())
                {
                    if (SwFrame *const pTmp = static_cast<SwLayoutFrame*>(pUp->GetNext())->ContainsAny())
                    {
                        pTmp->InvalidatePrt_();
                    }
                }
                if (!pUp->IsDeleteForbidden())
                {
                    pUp->Cut();
                    SwFrame::DestroyFrame(pUp);
                }
            }
            else if( aRectFnSet.GetHeight(getFrameArea()) )
            {
                // OD 26.08.2003 #i18103# - *no* 'ColUnlock' of section -
                // undo changes of fix for #104992#
                pUp->Shrink( getFrameArea().Height() );
            }
        }

        if ( pPage && !IsFollow() && pPage->GetUpper() )
            static_cast<SwRootFrame*>(pPage->GetUpper())->InvalidateBrowseWidth();
    }

    void SwTabFrame::Paste( SwFrame* pParent, SwFrame* pSibling )
    {
        OSL_ENSURE( pParent, "No parent for pasting." );
        OSL_ENSURE( pParent->IsLayoutFrame(), "Parent is ContentFrame." );
        OSL_ENSURE( pParent != this, "I'm the parent myself." );
        OSL_ENSURE( pSibling != this, "I'm my own neighbour." );
        OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(),
                "I'm still registered somewhere." );

        //Insert in the tree.
        InsertBefore( static_cast<SwLayoutFrame*>(pParent), pSibling );

        InvalidateAll_();
        SwPageFrame *pPage = FindPageFrame();
        InvalidatePage( pPage );

        if ( GetNext() )
        {
            GetNext()->InvalidatePos_();
            GetNext()->InvalidatePrt_();
            if ( GetNext()->IsContentFrame() )
                GetNext()->InvalidatePage( pPage );
        }

        SwRectFnSet aRectFnSet(this);
        if( aRectFnSet.GetHeight(getFrameArea()) )
            pParent->Grow( aRectFnSet.GetHeight(getFrameArea()) );

        if( aRectFnSet.GetWidth(getFrameArea()) != aRectFnSet.GetWidth(pParent->getFramePrintArea()) )
            Prepare( PREP_FIXSIZE_CHG );
        if ( GetPrev() )
        {
            if ( !IsFollow() )
            {
                GetPrev()->InvalidateSize();
                if ( GetPrev()->IsContentFrame() )
                    GetPrev()->InvalidatePage( pPage );
            }
        }
        else if ( GetNext() )
            //Take the margin into account when dealing with ContentFrame's. There are
            //two situations (both always happen at once):
            //a) The Content becomes the first in a chain
            //b) The new follower was the first in a chain before
            GetNext()->InvalidatePrt_();

        if ( pPage && !IsFollow() )
        {
            if ( pPage->GetUpper() )
                static_cast<SwRootFrame*>(pPage->GetUpper())->InvalidateBrowseWidth();

            if ( !GetPrev() )//At least needed for HTML with a table at the beginning.
            {
                const SwPageDesc *pDesc = GetFormat()->GetPageDesc().GetPageDesc();
                if ( (pDesc && pDesc != pPage->GetPageDesc()) ||
                     (!pDesc && pPage->GetPageDesc() != &GetFormat()->GetDoc()->GetPageDesc(0)) )
                    CheckPageDescs( pPage );
            }
        }
    }

    bool SwTabFrame::Prepare( const PrepareHint eHint, const void *, bool )
    {
        if( PREP_BOSS_CHGD == eHint )
            CheckDirChange();
        return false;
    }

    SwRowFrame::SwRowFrame(const SwTableLine &rLine, SwFrame* pSib, bool bInsertContent)
        : SwLayoutFrame( rLine.GetFrameFormat(), pSib )
        , m_pTabLine( &rLine )
        , m_pFollowRow( nullptr )
        // #i29550#
        , mnTopMarginForLowers( 0 )
        , mnBottomMarginForLowers( 0 )
        , mnBottomLineSize( 0 )
        // --> split table rows
        , m_bIsFollowFlowRow( false )
        // <-- split table rows
        , m_bIsRepeatedHeadline( false )
        , m_bIsRowSpanLine( false )
        , m_bIsInSplit( false )
    {
        mnFrameType = SwFrameType::Row;

        //Create the boxes and insert them.
        const SwTableBoxes &rBoxes = rLine.GetTabBoxes();
        SwFrame *pTmpPrev = nullptr;
        for ( size_t i = 0; i < rBoxes.size(); ++i )
        {
            SwCellFrame *pNew = new SwCellFrame( *rBoxes[i], this, bInsertContent );
            pNew->InsertBehind( this, pTmpPrev );
            pTmpPrev = pNew;
        }
    }

    void SwRowFrame::DestroyImpl()
    {
        SwModify* pMod = GetFormat();
        if( pMod )
        {
            pMod->Remove( this );           // remove,
            if( !pMod->HasWriterListeners() )
                delete pMod;                // and delete
        }

        SwLayoutFrame::DestroyImpl();
    }

    SwRowFrame::~SwRowFrame()
    {
    }

    void SwRowFrame::RegistFlys( SwPageFrame *pPage )
    {
        ::RegistFlys( pPage ? pPage : FindPageFrame(), this );
    }

    void SwRowFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew )
    {
        bool bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which();
        const SfxPoolItem *pItem = nullptr;

        if( bAttrSetChg )
        {
            const SwAttrSet* pChgSet = static_cast<const SwAttrSetChg*>(pNew)->GetChgSet();
            pChgSet->GetItemState( RES_FRM_SIZE, false, &pItem);
            if ( !pItem )
                pChgSet->GetItemState( RES_ROW_SPLIT, false, &pItem);
        }
        else if (pNew && (RES_FRM_SIZE == pNew->Which() || RES_ROW_SPLIT == pNew->Which()))
            pItem = pNew;

        if ( pItem )
        {
            SwTabFrame *pTab = FindTabFrame();
            if ( pTab )
            {
                const bool bInFirstNonHeadlineRow = pTab->IsFollow() &&
                                                    this == pTab->GetFirstNonHeadlineRow();
                // #i35063#
                // Invalidation required is pRow is last row
                if ( bInFirstNonHeadlineRow || !GetNext() )
                {
                    if ( bInFirstNonHeadlineRow )
                        pTab = pTab->FindMaster();
                    pTab->InvalidatePos();
                }
            }
        }

        SwLayoutFrame::Modify( pOld, pNew );
    }

    void SwRowFrame::MakeAll(vcl::RenderContext* pRenderContext)
    {
        if ( !GetNext() )
        {
            setFrameAreaSizeValid(false);
        }

        SwLayoutFrame::MakeAll(pRenderContext);
    }

    long CalcHeightWithFlys( const SwFrame *pFrame )
    {
        SwRectFnSet aRectFnSet(pFrame);
        long nHeight = 0;
        const SwFrame* pTmp = pFrame->IsSctFrame() ?
                static_cast<const SwSectionFrame*>(pFrame)->ContainsContent() : pFrame;
        while( pTmp )
        {
            // #i26945# - consider follow text frames
            const SwSortedObjs* pObjs( nullptr );
            bool bIsFollow( false );
            if ( pTmp->IsTextFrame() && static_cast<const SwTextFrame*>(pTmp)->IsFollow() )
            {
                const SwFrame* pMaster;
                // #i46450# Master does not necessarily have
                // to exist if this function is called from JoinFrame() ->
                // Cut() -> Shrink()
                const SwTextFrame* pTmpFrame = static_cast<const SwTextFrame*>(pTmp);
                if ( pTmpFrame->GetPrev() && pTmpFrame->GetPrev()->IsTextFrame() &&
                     static_cast<const SwTextFrame*>(pTmpFrame->GetPrev())->GetFollow() &&
                     static_cast<const SwTextFrame*>(pTmpFrame->GetPrev())->GetFollow() != pTmp )
                     pMaster = nullptr;
                else
                     pMaster = pTmpFrame->FindMaster();

                if ( pMaster )
                {
                     pObjs = static_cast<const SwTextFrame*>(pTmp)->FindMaster()->GetDrawObjs();
                    bIsFollow = true;
                }
            }
            else
            {
                pObjs = pTmp->GetDrawObjs();
            }
            if ( pObjs )
            {
                for (SwAnchoredObject* pAnchoredObj : *pObjs)
                {
                    // #i26945# - if <pTmp> is follow, the
                    // anchor character frame has to be <pTmp>.
                    if ( bIsFollow &&
                         pAnchoredObj->FindAnchorCharFrame() != pTmp )
                    {
                        continue;
                    }
                    // #i26945# - consider also drawing objects
                    {
                        // OD 30.09.2003 #i18732# - only objects, which follow
                        // the text flow have to be considered.
                        const SwFrameFormat& rFrameFormat = pAnchoredObj->GetFrameFormat();
                        const bool bConsiderObj =
                            (rFrameFormat.GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR) &&
                                pAnchoredObj->GetObjRect().Top() != FAR_AWAY &&
                                rFrameFormat.GetFollowTextFlow().GetValue() &&
                                pAnchoredObj->GetPageFrame() == pTmp->FindPageFrame();
                        if ( bConsiderObj )
                        {
                            const SwFormatFrameSize &rSz = rFrameFormat.GetFrameSize();
                            if( !rSz.GetHeightPercent() )
                            {
                                const SwTwips nDistOfFlyBottomToAnchorTop =
                                    aRectFnSet.GetHeight(pAnchoredObj->GetObjRect()) +
                                        ( aRectFnSet.IsVert() ?
                                          pAnchoredObj->GetCurrRelPos().X() :
                                          pAnchoredObj->GetCurrRelPos().Y() );

                                const SwTwips nFrameDiff =
                                    aRectFnSet.YDiff(
                                        aRectFnSet.GetTop(pTmp->getFrameArea()),
                                        aRectFnSet.GetTop(pFrame->getFrameArea()) );

                                nHeight = std::max( nHeight, nDistOfFlyBottomToAnchorTop + nFrameDiff -
                                                aRectFnSet.GetHeight(pFrame->getFrameArea()) );

                                // #i56115# The first height calculation
                                // gives wrong results if pFrame->getFramePrintArea().Y() > 0. We do
                                // a second calculation based on the actual rectangles of
                                // pFrame and pAnchoredObj, and use the maximum of the results.
                                // I do not want to remove the first calculation because
                                // if clipping has been applied, using the GetCurrRelPos
                                // might be the better option to calculate nHeight.
                                const SwTwips nDistOfFlyBottomToAnchorTop2 = aRectFnSet.YDiff(
                                                                                aRectFnSet.GetBottom(pAnchoredObj->GetObjRect()),
                                                                                aRectFnSet.GetBottom(pFrame->getFrameArea()) );

                                nHeight = std::max( nHeight, nDistOfFlyBottomToAnchorTop2 );
                            }
                        }
                    }
                }
            }
            if( !pFrame->IsSctFrame() )
                break;
            pTmp = pTmp->FindNextCnt();
            if( !static_cast<const SwSectionFrame*>(pFrame)->IsAnLower( pTmp ) )
                break;
        }
        return nHeight;
    }

    static SwTwips lcl_CalcTopAndBottomMargin( const SwLayoutFrame& rCell, const SwBorderAttrs& rAttrs )
    {
        const SwTabFrame* pTab = rCell.FindTabFrame();
        SwTwips nTopSpace = 0;
        SwTwips nBottomSpace = 0;

        // #i29550#
        if ( pTab->IsCollapsingBorders() && rCell.Lower() && !rCell.Lower()->IsRowFrame() )
        {
            nTopSpace    = static_cast<const SwRowFrame*>(rCell.GetUpper())->GetTopMarginForLowers();
            nBottomSpace = static_cast<const SwRowFrame*>(rCell.GetUpper())->GetBottomMarginForLowers();
        }
        else
        {
            if ( pTab->IsVertical() != rCell.IsVertical() )
            {
                nTopSpace    = rAttrs.CalcLeft( &rCell );
                nBottomSpace = rAttrs.CalcRight( &rCell );
            }
            else
            {
                nTopSpace    = rAttrs.CalcTop();
                nBottomSpace = rAttrs.CalcBottom();
            }
        }

        return nTopSpace + nBottomSpace;
    }

    // #i26945# - add parameter <_bConsiderObjs> in order to
    // control, if floating screen objects have to be considered for the minimal
    // cell height.
    static SwTwips lcl_CalcMinCellHeight( const SwLayoutFrame *_pCell,
                                          const bool _bConsiderObjs,
                                          const SwBorderAttrs *pAttrs = nullptr )
    {
        SwRectFnSet aRectFnSet(_pCell);
        SwTwips nHeight = 0;
        const SwFrame* pLow = _pCell->Lower();
        if ( pLow )
        {
            long nFlyAdd = 0;
            while ( pLow )
            {
                // OD 2004-02-18 #106629# - change condition and switch then-body
                // and else-body
                if ( pLow->IsRowFrame() )
                {
                    // #i26945#
                    nHeight += ::lcl_CalcMinRowHeight( static_cast<const SwRowFrame*>(pLow),
                                                       _bConsiderObjs );
                }
                else
                {
                    long nLowHeight = aRectFnSet.GetHeight(pLow->getFrameArea());
                    nHeight += nLowHeight;
                    // #i26945#
                    if ( _bConsiderObjs )
                    {
                        nFlyAdd = std::max( 0L, nFlyAdd - nLowHeight );
                        nFlyAdd = std::max( nFlyAdd, ::CalcHeightWithFlys( pLow ) );
                    }
                }

                pLow = pLow->GetNext();
            }
            if ( nFlyAdd )
                nHeight += nFlyAdd;
        }
        //The border needs to be considered too, unfortunately it can't be
        //calculated using PrtArea and Frame because those can be invalid in arbitrary
        //combinations.
        if ( _pCell->Lower() )
        {
            if ( pAttrs )
                nHeight += lcl_CalcTopAndBottomMargin( *_pCell, *pAttrs );
            else
            {
                SwBorderAttrAccess aAccess( SwFrame::GetCache(), _pCell );
                const SwBorderAttrs &rAttrs = *aAccess.Get();
                nHeight += lcl_CalcTopAndBottomMargin( *_pCell, rAttrs );
            }
        }
        return nHeight;
    }

    // OD 2004-02-18 #106629# - correct type of 1st parameter
    // #i26945# - add parameter <_bConsiderObjs> in order to control,
    // if floating screen objects have to be considered for the minimal cell height
    static SwTwips lcl_CalcMinRowHeight( const SwRowFrame* _pRow,
                                         const bool _bConsiderObjs )
    {
        SwTwips nHeight = 0;
        if ( !_pRow->IsRowSpanLine() )
        {
            const SwFormatFrameSize &rSz = _pRow->GetFormat()->GetFrameSize();
            if ( _pRow->HasFixSize() )
            {
                OSL_ENSURE(ATT_FIX_SIZE == rSz.GetHeightSizeType(), "pRow claims to have fixed size");
                return rSz.GetHeight();
            }
            // If this row frame is being split, then row's minimal height shouldn't restrict
            // this frame's minimal height, because the rest will go to follow frame.
            else if ( !_pRow->IsInSplit() && rSz.GetHeightSizeType() == ATT_MIN_SIZE )
            {
                nHeight = rSz.GetHeight() - lcl_calcHeightOfRowBeforeThisFrame(*_pRow);
            }
        }

        SwRectFnSet aRectFnSet(_pRow);
        const SwCellFrame* pLow = static_cast<const SwCellFrame*>(_pRow->Lower());
        while ( pLow )
        {
            SwTwips nTmp = 0;
            const long nRowSpan = pLow->GetLayoutRowSpan();
            // --> NEW TABLES
            // Consider height of
            // 1. current cell if RowSpan == 1
            // 2. current cell if cell is "follow" cell of a cell with RowSpan == -1
            // 3. master cell if RowSpan == -1
            if ( 1 == nRowSpan )
            {
                nTmp = ::lcl_CalcMinCellHeight( pLow, _bConsiderObjs );
            }
            else if ( -1 == nRowSpan )
            {
                // Height of the last cell of a row span is height of master cell
                // minus the height of the other rows which are covered by the master
                // cell:
                const SwCellFrame& rMaster = pLow->FindStartEndOfRowSpanCell( true );
                nTmp = ::lcl_CalcMinCellHeight( &rMaster, _bConsiderObjs );
                const SwFrame* pMasterRow = rMaster.GetUpper();
                while ( pMasterRow && pMasterRow != _pRow )
                {
                    nTmp -= aRectFnSet.GetHeight(pMasterRow->getFrameArea());
                    pMasterRow = pMasterRow->GetNext();
                }
            }
            // <-- NEW TABLES

            // Do not consider rotated cells:
            if ( pLow->IsVertical() == aRectFnSet.IsVert() && nTmp > nHeight )
                nHeight = nTmp;

            pLow = static_cast<const SwCellFrame*>(pLow->GetNext());
        }

        return nHeight;
    }

    // #i29550#

    // Calculate the maximum of (TopLineSize + TopLineDist) over all lowers:
    static sal_uInt16 lcl_GetTopSpace( const SwRowFrame& rRow )
    {
        sal_uInt16 nTopSpace = 0;
        for ( const SwCellFrame* pCurrLower = static_cast<const SwCellFrame*>(rRow.Lower()); pCurrLower;
              pCurrLower = static_cast<const SwCellFrame*>(pCurrLower->GetNext()) )
        {
            sal_uInt16 nTmpTopSpace = 0;
            if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrame() )
                nTmpTopSpace = lcl_GetTopSpace( *static_cast<const SwRowFrame*>(pCurrLower->Lower()) );
            else
            {
                const SwAttrSet& rSet = const_cast<SwCellFrame*>(pCurrLower)->GetFormat()->GetAttrSet();
                const SvxBoxItem& rBoxItem = rSet.GetBox();
                nTmpTopSpace = rBoxItem.CalcLineSpace( SvxBoxItemLine::TOP, true );
            }
            nTopSpace  = std::max( nTopSpace, nTmpTopSpace );
        }
        return nTopSpace;
    }

    // Calculate the maximum of TopLineDist over all lowers:
    static sal_uInt16 lcl_GetTopLineDist( const SwRowFrame& rRow )
    {
        sal_uInt16 nTopLineDist = 0;
        for ( const SwCellFrame* pCurrLower = static_cast<const SwCellFrame*>(rRow.Lower()); pCurrLower;
              pCurrLower = static_cast<const SwCellFrame*>(pCurrLower->GetNext()) )
        {
            sal_uInt16 nTmpTopLineDist = 0;
            if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrame() )
                nTmpTopLineDist = lcl_GetTopLineDist( *static_cast<const SwRowFrame*>(pCurrLower->Lower()) );
            else
            {
                const SwAttrSet& rSet = const_cast<SwCellFrame*>(pCurrLower)->GetFormat()->GetAttrSet();
                const SvxBoxItem& rBoxItem = rSet.GetBox();
                nTmpTopLineDist = rBoxItem.GetDistance( SvxBoxItemLine::TOP );
            }
            nTopLineDist = std::max( nTopLineDist, nTmpTopLineDist );
        }
        return nTopLineDist;
    }

    // Calculate the maximum of BottomLineSize over all lowers:
    static sal_uInt16 lcl_GetBottomLineSize( const SwRowFrame& rRow )
    {
        sal_uInt16 nBottomLineSize = 0;
        for ( const SwCellFrame* pCurrLower = static_cast<const SwCellFrame*>(rRow.Lower()); pCurrLower;
              pCurrLower = static_cast<const SwCellFrame*>(pCurrLower->GetNext()) )
        {
            sal_uInt16 nTmpBottomLineSize = 0;
            if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrame() )
            {
                const SwFrame* pRow = pCurrLower->GetLastLower();
                nTmpBottomLineSize = lcl_GetBottomLineSize( *static_cast<const SwRowFrame*>(pRow) );
            }
            else
            {
                const SwAttrSet& rSet = const_cast<SwCellFrame*>(pCurrLower)->GetFormat()->GetAttrSet();
                const SvxBoxItem& rBoxItem = rSet.GetBox();
                nTmpBottomLineSize = rBoxItem.CalcLineSpace( SvxBoxItemLine::BOTTOM, true ) -
                                     rBoxItem.GetDistance( SvxBoxItemLine::BOTTOM );
            }
            nBottomLineSize = std::max( nBottomLineSize, nTmpBottomLineSize );
        }
        return nBottomLineSize;
    }

    // Calculate the maximum of BottomLineDist over all lowers:
    static sal_uInt16 lcl_GetBottomLineDist( const SwRowFrame& rRow )
    {
        sal_uInt16 nBottomLineDist = 0;
        for ( const SwCellFrame* pCurrLower = static_cast<const SwCellFrame*>(rRow.Lower()); pCurrLower;
              pCurrLower = static_cast<const SwCellFrame*>(pCurrLower->GetNext()) )
        {
            sal_uInt16 nTmpBottomLineDist = 0;
            if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrame() )
            {
                const SwFrame* pRow = pCurrLower->GetLastLower();
                nTmpBottomLineDist = lcl_GetBottomLineDist( *static_cast<const SwRowFrame*>(pRow) );
            }
            else
            {
                const SwAttrSet& rSet = const_cast<SwCellFrame*>(pCurrLower)->GetFormat()->GetAttrSet();
                const SvxBoxItem& rBoxItem = rSet.GetBox();
                nTmpBottomLineDist = rBoxItem.GetDistance( SvxBoxItemLine::BOTTOM );
            }
            nBottomLineDist = std::max( nBottomLineDist, nTmpBottomLineDist );
        }
        return nBottomLineDist;
    }

    // tdf#104425: calculate the height of all row frames,
    // for which this frame is a follow.
    // When a row has fixed/minimum height, it may span over
    // several pages. The minimal height on this page should
    // take into account the sum of all the heights of previous
    // frames that constitute the table row on previous pages.
    // Otherwise, trying to split a too high row frame will
    // result in loop trying to create that too high row
    // on each following page
    static SwTwips lcl_calcHeightOfRowBeforeThisFrame(const SwRowFrame& rRow)
    {
        // We don't need to account for previous instances of repeated headlines
        if (rRow.IsRepeatedHeadline())
            return 0;
        SwRectFnSet aRectFnSet(&rRow);
        const SwTableLine* pLine = rRow.GetTabLine();
        const SwTabFrame* pTab = rRow.FindTabFrame();
        if (!pLine || !pTab || !pTab->IsFollow())
            return 0;
        SwTwips nResult = 0;
        SwIterator<SwRowFrame, SwFormat> aIter(*pLine->GetFrameFormat());
        for (const SwRowFrame* pCurRow = aIter.First(); pCurRow; pCurRow = aIter.Next())
        {
            if (pCurRow != &rRow && pCurRow->GetTabLine() == pLine)
            {
                // We've found another row frame that is part of the same table row
                const SwTabFrame* pCurTab = pCurRow->FindTabFrame();
                // A row frame may not belong to a table frame, when it is being cut, e.g., in
                // lcl_PostprocessRowsInCells().
                // Its SwRowFrame::Cut() has been called; it in turn called SwLayoutFrame::Cut(),
                // which nullified row's upper in RemoveFromLayout(), and then called Shrink()
                // for its former upper.
                // Regardless of whether it will be pasted back, or destroyed, currently it's not
                // part of layout, and its height does not count
                if (pCurTab && pCurTab->IsAnFollow(pTab))
                {
                    // The found row frame belongs to a table frame that precedes
                    // (above) this one in chain. So, include it in the sum
                    nResult += aRectFnSet.GetHeight(pCurRow->getFrameArea());
                }
            }
        }
        return nResult;
    }

    void SwRowFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs *pAttrs )
    {
        SwRectFnSet aRectFnSet(this);
        OSL_ENSURE( pAttrs, "SwRowFrame::Format without Attrs." );

        const bool bFix = mbFixSize;

        if ( !isFramePrintAreaValid() )
        {
            //RowFrames don't have borders and so on therefore the PrtArea always
            //matches the Frame.
            setFramePrintAreaValid(true);

            {
                SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
                aPrt.Left( 0 );
                aPrt.Top( 0 );
                aPrt.Width ( getFrameArea().Width() );
                aPrt.Height( getFrameArea().Height() );
            }

            // #i29550#
            // Here we calculate the top-printing area for the lower cell frames
            SwTabFrame* pTabFrame = FindTabFrame();
            if ( pTabFrame->IsCollapsingBorders() )
            {
                const sal_uInt16 nTopSpace        = lcl_GetTopSpace(       *this );
                const sal_uInt16 nTopLineDist     = lcl_GetTopLineDist(    *this );
                const sal_uInt16 nBottomLineSize  = lcl_GetBottomLineSize( *this );
                const sal_uInt16 nBottomLineDist  = lcl_GetBottomLineDist( *this );

                const SwRowFrame* pPreviousRow = nullptr;

                // #i32456#
                // In order to calculate the top printing area for the lower cell
                // frames, we have to find the 'previous' row frame and compare
                // the bottom values of the 'previous' row with the 'top' values
                // of this row. The best way to find the 'previous' row is to
                // use the table structure:
                const SwTable* pTable = pTabFrame->GetTable();
                const SwTableLine* pPrevTabLine = nullptr;
                const SwRowFrame* pTmpRow = this;

                while ( pTmpRow && !pPrevTabLine )
                {
                    size_t nIdx = 0;
                    const SwTableLines& rLines = pTmpRow->GetTabLine()->GetUpper() ?
                                                 pTmpRow->GetTabLine()->GetUpper()->GetTabLines() :
                                                 pTable->GetTabLines();

                    while ( rLines[ nIdx ] != pTmpRow->GetTabLine() )
                        ++nIdx;

                    if ( nIdx > 0 )
                    {
                        // pTmpRow has a 'previous' row in the table structure:
                        pPrevTabLine = rLines[ nIdx - 1 ];
                    }
                    else
                    {
                        // pTmpRow is a first row in the table structure.
                        // We go up in the table structure:
                        pTmpRow = pTmpRow->GetUpper()->GetUpper() &&
                                  pTmpRow->GetUpper()->GetUpper()->IsRowFrame() ?
                                  static_cast<const SwRowFrame*>( pTmpRow->GetUpper()->GetUpper() ) :
                                  nullptr;
                    }
                }

                // If we found a 'previous' row, we look for the appropriate row frame:
                if ( pPrevTabLine )
                {
                    SwIterator<SwRowFrame,SwFormat> aIter( *pPrevTabLine->GetFrameFormat() );
                    for ( SwRowFrame* pRow = aIter.First(); pRow; pRow = aIter.Next() )
                    {
                        // #115759# - do *not* take repeated
                        // headlines, because during split of table it can be
                        // invalid and thus can't provide correct border values.
                        if ( pRow->GetTabLine() == pPrevTabLine &&
                             !pRow->IsRepeatedHeadline() )
                        {
                            pPreviousRow = pRow;
                            break;
                        }
                    }
                }

                sal_uInt16 nTopPrtMargin = nTopSpace;
                if ( pPreviousRow )
                {
                    const sal_uInt16 nTmpPrtMargin = pPreviousRow->GetBottomLineSize() + nTopLineDist;
                    if ( nTmpPrtMargin > nTopPrtMargin )
                        nTopPrtMargin = nTmpPrtMargin;
                }

                // table has to be notified if it has to change its lower
                // margin due to changes of nBottomLineSize:
                if ( !GetNext() && nBottomLineSize != GetBottomLineSize() )
                     pTabFrame->InvalidatePrt_();

                // If there are rows nested inside this row, the nested rows
                // may not have been calculated yet. Therefore the
                // ::lcl_CalcMinRowHeight( this ) operation later in this
                // function cannot consider the correct border values. We
                // have to trigger the invalidation of the outer row frame
                // manually:
                // Note: If any further invalidations should be necessary, we
                // should consider moving the invalidation stuff to the
                // appropriate SwNotify object.
                if ( GetUpper()->GetUpper()->IsRowFrame() &&
                     ( nBottomLineDist != GetBottomMarginForLowers() ||
                       nTopPrtMargin   != GetTopMarginForLowers() ) )
                    GetUpper()->GetUpper()->InvalidateSize_();

                SetBottomMarginForLowers( nBottomLineDist );    //  3.
                SetBottomLineSize( nBottomLineSize );           //  4.
                SetTopMarginForLowers( nTopPrtMargin );         //  5.

            }
        }

        while ( !isFrameAreaSizeValid() )
        {
            setFrameAreaSizeValid(true);

    #if OSL_DEBUG_LEVEL > 0
            if ( HasFixSize() )
            {
                const SwFormatFrameSize &rFrameSize = GetFormat()->GetFrameSize();
                OSL_ENSURE( rFrameSize.GetSize().Height() > 0, "Has it" );
            }
    #endif
            const SwTwips nDiff = aRectFnSet.GetHeight(getFrameArea()) -
                                  ( HasFixSize() && !IsRowSpanLine()
                                    ? pAttrs->GetSize().Height()
                                    // #i26945#
                                    : ::lcl_CalcMinRowHeight( this,
                                        FindTabFrame()->IsConsiderObjsForMinCellHeight() ) );
            if ( nDiff )
            {
                mbFixSize = false;
                if ( nDiff > 0 )
                    Shrink( nDiff, false, true );
                else if ( nDiff < 0 )
                    Grow( -nDiff );
                mbFixSize = bFix;
            }
        }

        // last row will fill the space in its upper.
        if ( !GetNext() )
        {
            //The last fills the remaining space in the upper.
            SwTwips nDiff = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea());
            SwFrame *pSibling = GetUpper()->Lower();
            do
            {   nDiff -= aRectFnSet.GetHeight(pSibling->getFrameArea());
                pSibling = pSibling->GetNext();
            } while ( pSibling );
            if ( nDiff > 0 )
            {
                mbFixSize = false;
                Grow( nDiff );
                mbFixSize = bFix;
                setFrameAreaSizeValid(true);
            }
        }
    }

    void SwRowFrame::AdjustCells( const SwTwips nHeight, const bool bHeight )
    {
        SwFrame *pFrame = Lower();
        if ( bHeight )
        {
            SwRootFrame *pRootFrame = getRootFrame();
            SwRectFnSet aRectFnSet(this);
            SwRect aOldFrame;

            while ( pFrame )
            {
                SwFrame* pNotify = nullptr;

                SwCellFrame* pCellFrame = static_cast<SwCellFrame*>(pFrame);

                // NEW TABLES
                // Which cells need to be adjusted if the current row changes
                // its height?

                // Current frame is a covered frame:
                // Set new height for covered cell and adjust master cell:
                if ( pCellFrame->GetTabBox()->getRowSpan() < 1 )
                {
                    // Set height of current (covered) cell to new line height.
                    const long nDiff = nHeight - aRectFnSet.GetHeight(pCellFrame->getFrameArea());
                    if ( nDiff )
                    {
                        {
                            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pCellFrame);
                            aRectFnSet.AddBottom( aFrm, nDiff );
                        }

                        pCellFrame->InvalidatePrt_();
                    }
                }

                SwCellFrame* pToAdjust = nullptr;
                SwFrame* pToAdjustRow = nullptr;

                // If current frame is covered frame, we still want to adjust the
                // height of the cell starting the row span
                if ( pCellFrame->GetLayoutRowSpan() < 1 )
                {
                    pToAdjust = const_cast< SwCellFrame*>(&pCellFrame->FindStartEndOfRowSpanCell( true ));
                    pToAdjustRow = pToAdjust->GetUpper();
                }
                else
                {
                    pToAdjust = pCellFrame;
                    pToAdjustRow = this;
                }

                // Set height of master cell to height of all lines spanned by this line.
                long nRowSpan = pToAdjust->GetLayoutRowSpan();
                SwTwips nSumRowHeight = 0;
                while ( pToAdjustRow )
                {
                    // Use new height for the current row:
                    nSumRowHeight += pToAdjustRow == this ?
                                     nHeight :
                                     aRectFnSet.GetHeight(pToAdjustRow->getFrameArea());

                    if ( nRowSpan-- == 1 )
                        break;

                    pToAdjustRow = pToAdjustRow->GetNext();
                }

                if ( pToAdjustRow && pToAdjustRow != this )
                    pToAdjustRow->InvalidateSize_();

                const long nDiff = nSumRowHeight - aRectFnSet.GetHeight(pToAdjust->getFrameArea());
                if ( nDiff )
                {
                    aOldFrame = pToAdjust->getFrameArea();
                    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pToAdjust);
                    aRectFnSet.AddBottom( aFrm, nDiff );
                    pNotify = pToAdjust;
                }

                if ( pNotify )
                {
                    if( pRootFrame && pRootFrame->IsAnyShellAccessible() && pRootFrame->GetCurrShell() )
                        pRootFrame->GetCurrShell()->Imp()->MoveAccessibleFrame( pNotify, aOldFrame );

                    pNotify->InvalidatePrt_();
                }

                pFrame = pFrame->GetNext();
            }
        }
        else
        {   while ( pFrame )
            {
                pFrame->InvalidateAll_();
                pFrame = pFrame->GetNext();
            }
        }
        InvalidatePage();
    }

    void SwRowFrame::Cut()
    {
        SwTabFrame *pTab = FindTabFrame();
        if ( pTab && pTab->IsFollow() && this == pTab->GetFirstNonHeadlineRow() )
        {
            pTab->FindMaster()->InvalidatePos();
        }

        SwLayoutFrame::Cut();
    }

    SwTwips SwRowFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo )
    {
        SwTwips nReal = 0;

        SwTabFrame* pTab = FindTabFrame();
        SwRectFnSet aRectFnSet(pTab);

        bool bRestrictTableGrowth;
        bool bHasFollowFlowLine = pTab->HasFollowFlowLine();

        if ( GetUpper()->IsTabFrame() )
        {
            const SwRowFrame* pFollowFlowRow = IsInSplitTableRow();
            bRestrictTableGrowth = pFollowFlowRow && !pFollowFlowRow->IsRowSpanLine();
        }
        else
        {
            OSL_ENSURE( GetUpper()->IsCellFrame(), "RowFrame->GetUpper neither table nor cell" );
            bRestrictTableGrowth = GetFollowRow() && bHasFollowFlowLine;
            OSL_ENSURE( !bRestrictTableGrowth || !GetNext(),
                    "GetFollowRow for row frame that has a Next" );

            // There may still be some space left in my direct upper:
            const SwTwips nAdditionalSpace =
                    aRectFnSet.BottomDist( getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()->GetUpper()) );
            if ( bRestrictTableGrowth && nAdditionalSpace > 0 )
            {
                nReal = std::min( nAdditionalSpace, nDist );
                nDist -= nReal;
                if ( !bTst )
                {
                    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                    aRectFnSet.AddBottom( aFrm, nReal );
                }
            }
        }

        if ( bRestrictTableGrowth )
            pTab->SetRestrictTableGrowth( true );
        else
        {
            // Ok, this looks like a hack, indeed, it is a hack.
            // If the current row frame is inside another cell frame,
            // and the current row frame has no follow, it should not
            // be allowed to grow. In fact, setting bRestrictTableGrowth
            // to 'false' does not work, because the surrounding RowFrame
            // would set this to 'true'.
            pTab->SetFollowFlowLine( false );
        }

        nReal += SwLayoutFrame::GrowFrame( nDist, bTst, bInfo);

        pTab->SetRestrictTableGrowth( false );
        pTab->SetFollowFlowLine( bHasFollowFlowLine );

        //Update the height of the cells to the newest value.
        if ( !bTst )
        {
            SwRectFnSet fnRectX(this);
            AdjustCells( fnRectX.GetHeight(getFramePrintArea()) + nReal, true );
            if ( nReal )
                SetCompletePaint();
        }

        return nReal;
    }

    SwTwips SwRowFrame::ShrinkFrame( SwTwips nDist, bool bTst, bool bInfo )
    {
        SwRectFnSet aRectFnSet(this);
        if( HasFixSize() )
        {
            AdjustCells( aRectFnSet.GetHeight(getFramePrintArea()), true );
            return 0;
        }

        // bInfo may be set to true by SwRowFrame::Format; we need to handle this
        // here accordingly
        const bool bShrinkAnyway = bInfo;

        //Only shrink as much as the content of the biggest cell allows.
        SwTwips nRealDist = nDist;
        SwFormat* pMod = GetFormat();
        if (pMod)
        {
            const SwFormatFrameSize &rSz = pMod->GetFrameSize();
            SwTwips nMinHeight = 0;
            if (rSz.GetHeightSizeType() == ATT_MIN_SIZE)
                nMinHeight = std::max(rSz.GetHeight() - lcl_calcHeightOfRowBeforeThisFrame(*this),
                                      0L);

            // Only necessary to calculate minimal row height if height
            // of pRow is at least nMinHeight. Otherwise nMinHeight is the
            // minimum height.
            if( nMinHeight < aRectFnSet.GetHeight(getFrameArea()) )
            {
                // #i26945#
                OSL_ENSURE( FindTabFrame(), "<SwRowFrame::ShrinkFrame(..)> - no table frame -> crash." );
                const bool bConsiderObjs( FindTabFrame()->IsConsiderObjsForMinCellHeight() );
                nMinHeight = lcl_CalcMinRowHeight( this, bConsiderObjs );
            }

            if ( (aRectFnSet.GetHeight(getFrameArea()) - nRealDist) < nMinHeight )
                nRealDist = aRectFnSet.GetHeight(getFrameArea()) - nMinHeight;
        }
        if ( nRealDist < 0 )
            nRealDist = 0;

        SwTwips nReal = nRealDist;
        if ( nReal )
        {
            if ( !bTst )
            {
                SwTwips nHeight = aRectFnSet.GetHeight(getFrameArea());
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                aRectFnSet.SetHeight( aFrm, nHeight - nReal );

                if( IsVertical() && !IsVertLR() )
                {
                    aFrm.Pos().AdjustX(nReal );
                }
            }

            SwLayoutFrame* pFrame = GetUpper();
            SwTwips nTmp = pFrame ? pFrame->Shrink(nReal, bTst) : 0;
            if ( !bShrinkAnyway && !GetNext() && nTmp != nReal )
            {
                //The last one gets the leftover in the upper and therefore takes
                //care (otherwise: endless loop)
                if ( !bTst )
                {
                    nReal -= nTmp;
                    SwTwips nHeight = aRectFnSet.GetHeight(getFrameArea());
                    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
                    aRectFnSet.SetHeight( aFrm, nHeight + nReal );

                    if( IsVertical() && !IsVertLR() )
                    {
                        aFrm.Pos().AdjustX( -nReal );
                    }
                }
                nReal = nTmp;
            }
        }

        //Invalidate if possible and update the height to the newest value.
        if ( !bTst )
        {
            if ( nReal )
            {
                if ( GetNext() )
                    GetNext()->InvalidatePos_();
                InvalidateAll_();
                SetCompletePaint();

                SwTabFrame *pTab = FindTabFrame();
                if ( !pTab->IsRebuildLastLine()
                     && pTab->IsFollow()
                     && this == pTab->GetFirstNonHeadlineRow()
                     && !pTab->IsInRecalcLowerRow() )
                {
                    SwTabFrame* pMasterTab = pTab->FindMaster();
                    pMasterTab->InvalidatePos();
                }
            }
            AdjustCells( aRectFnSet.GetHeight(getFramePrintArea()) - nReal, true );
        }
        return nReal;
    }

    bool SwRowFrame::IsRowSplitAllowed() const
    {
        // Fixed size rows are never allowed to split:
        if ( HasFixSize() )
        {
            OSL_ENSURE( ATT_FIX_SIZE == GetFormat()->GetFrameSize().GetHeightSizeType(), "pRow claims to have fixed size" );
            return false;
        }

        // Repeated headlines are never allowed to split:
        const SwTabFrame* pTabFrame = FindTabFrame();
        if ( pTabFrame->GetTable()->GetRowsToRepeat() > 0 &&
             pTabFrame->IsInHeadline( *this ) )
            return false;

        const SwTableLineFormat* pFrameFormat = static_cast<SwTableLineFormat*>(GetTabLine()->GetFrameFormat());
        const SwFormatRowSplit& rLP = pFrameFormat->GetRowSplit();
        return rLP.GetValue();
    }

    bool SwRowFrame::ShouldRowKeepWithNext( const bool bCheckParents ) const
    {
        // No KeepWithNext if nested in another table
        if ( GetUpper()->GetUpper()->IsCellFrame() )
            return false;

        const SwCellFrame* pCell = static_cast<const SwCellFrame*>(Lower());
        const SwFrame* pText = pCell->Lower();

        return pText && pText->IsTextFrame() &&
               static_cast<const SwTextFrame*>(pText)->GetTextNodeForParaProps()->GetSwAttrSet().GetKeep(bCheckParents).GetValue();
    }

    SwCellFrame::SwCellFrame(const SwTableBox &rBox, SwFrame* pSib, bool bInsertContent)
        : SwLayoutFrame( rBox.GetFrameFormat(), pSib )
        , m_pTabBox( &rBox )
    {
        mnFrameType = SwFrameType::Cell;

        if ( !bInsertContent )
            return;

        //If a StartIdx is available, ContentFrames are added in the cell, otherwise
        //Rows have to be present and those are added.
        if ( rBox.GetSttIdx() )
        {
            sal_uLong nIndex = rBox.GetSttIdx();
            ::InsertCnt_( this, rBox.GetFrameFormat()->GetDoc(), ++nIndex );
        }
        else
        {
            const SwTableLines &rLines = rBox.GetTabLines();
            SwFrame *pTmpPrev = nullptr;
            for ( size_t i = 0; i < rLines.size(); ++i )
            {
                SwRowFrame *pNew = new SwRowFrame( *rLines[i], this, bInsertContent );
                pNew->InsertBehind( this, pTmpPrev );
                pTmpPrev = pNew;
            }
        }
    }

    void SwCellFrame::DestroyImpl()
    {
        SwModify* pMod = GetFormat();
        if( pMod )
        {
            // At this stage the lower frames aren't destroyed already,
            // therefore we have to do a recursive dispose.
            SwRootFrame *pRootFrame = getRootFrame();
            if( pRootFrame && pRootFrame->IsAnyShellAccessible() &&
                pRootFrame->GetCurrShell() )
            {
                pRootFrame->GetCurrShell()->Imp()->DisposeAccessibleFrame( this, true );
            }

            pMod->Remove( this );           // remove,
            if( !pMod->HasWriterListeners() )
                delete pMod;                // and delete
        }

        SwLayoutFrame::DestroyImpl();
    }

    SwCellFrame::~SwCellFrame()
    {
    }

    static bool lcl_ArrangeLowers( SwLayoutFrame *pLay, long lYStart, bool bInva )
    {
        bool bRet = false;
        SwFrame *pFrame = pLay->Lower();
        SwRectFnSet aRectFnSet(pLay);
        while ( pFrame )
        {
            long nFrameTop = aRectFnSet.GetTop(pFrame->getFrameArea());
            if( nFrameTop != lYStart )
            {
                bRet = true;
                const long lDiff = aRectFnSet.YDiff( lYStart, nFrameTop );
                const long lDiffX = lYStart - nFrameTop;

                {
                    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFrame);
                    aRectFnSet.SubTop( aFrm, -lDiff );
                    aRectFnSet.AddBottom( aFrm, lDiff );
                }

                pFrame->SetCompletePaint();

                if ( !pFrame->GetNext() )
                    pFrame->SetRetouche();
                if( bInva )
                    pFrame->Prepare( PREP_POS_CHGD );
                if ( pFrame->IsLayoutFrame() && static_cast<SwLayoutFrame*>(pFrame)->Lower() )
                    lcl_ArrangeLowers( static_cast<SwLayoutFrame*>(pFrame),
                        aRectFnSet.GetTop(static_cast<SwLayoutFrame*>(pFrame)->Lower()->getFrameArea())
                        + lDiffX, bInva );
                if ( pFrame->GetDrawObjs() )
                {
                    for ( size_t i = 0; i < pFrame->GetDrawObjs()->size(); ++i )
                    {
                        SwAnchoredObject* pAnchoredObj = (*pFrame->GetDrawObjs())[i];
                        // #i26945# - check, if anchored object
                        // is lower of layout frame by checking, if the anchor
                        // frame, which contains the anchor position, is a lower
                        // of the layout frame.
                        if ( !pLay->IsAnLower( pAnchoredObj->GetAnchorFrameContainingAnchPos() ) )
                        {
                            continue;
                        }
                        // #i52904# - distinguish between anchored
                        // objects, whose vertical position depends on its anchor
                        // frame and whose vertical position is independent
                        // from its anchor frame.
                        bool bVertPosDepOnAnchor( true );
                        {
                            SwFormatVertOrient aVert( pAnchoredObj->GetFrameFormat().GetVertOrient() );
                            switch ( aVert.GetRelationOrient() )
                            {
                                case text::RelOrientation::PAGE_FRAME:
                                case text::RelOrientation::PAGE_PRINT_AREA:
                                    bVertPosDepOnAnchor = false;
                                    break;
                                default: break;
                            }
                        }
                        if ( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) !=  nullptr )
                        {
                            SwFlyFrame *pFly = static_cast<SwFlyFrame*>(pAnchoredObj);

                            // OD 2004-05-18 #i28701# - no direct move of objects,
                            // which are anchored to-paragraph/to-character, if
                            // the wrapping style influence has to be considered
                            // on the object positioning.
                            // #i52904# - no direct move of objects,
                            // whose vertical position doesn't depend on anchor frame.
                            const bool bDirectMove =
                                    FAR_AWAY != pFly->getFrameArea().Top() &&
                                    bVertPosDepOnAnchor &&
                                    !pFly->ConsiderObjWrapInfluenceOnObjPos();
                            if ( bDirectMove )
                            {
                                {
                                    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFly);
                                    aRectFnSet.SubTop( aFrm, -lDiff );
                                    aRectFnSet.AddBottom( aFrm, lDiff );
                                }

                                pFly->GetVirtDrawObj()->SetRectsDirty();
                                // --> OD 2004-08-17 - also notify view of <SdrObject>
                                // instance, which represents the Writer fly frame in
                                // the drawing layer
                                pFly->GetVirtDrawObj()->SetChanged();
                                // #i58280#
                                pFly->InvalidateObjRectWithSpaces();
                            }

                            if ( pFly->IsFlyInContentFrame() )
                            {
                                static_cast<SwFlyInContentFrame*>(pFly)->AddRefOfst( lDiff );
                                // #115759# - reset current relative
                                // position to get re-positioned, if not directly moved.
                                if ( !bDirectMove )
                                {
                                    pAnchoredObj->SetCurrRelPos( Point( 0, 0 ) );
                                }
                            }
                            else if( pFly->IsAutoPos() )
                            {
                                pFly->AddLastCharY( lDiff );
                                // OD 2004-05-18 #i28701# - follow-up of #i22341#
                                // <mnLastTopOfLine> has also been adjusted.
                                pFly->AddLastTopOfLineY( lDiff );
                            }
                            // #i26945# - re-registration at
                            // page frame of anchor frame, if table frame isn't
                            // a follow table and table frame isn't in its
                            // rebuild of last line.
                            const SwTabFrame* pTabFrame = pLay->FindTabFrame();
                            // - save: check, if table frame is found.
                            if ( pTabFrame &&
                                 !( pTabFrame->IsFollow() &&
                                    pTabFrame->FindMaster()->IsRebuildLastLine() ) &&
                                 pFly->IsFlyFreeFrame() )
                            {
                                SwPageFrame* pPageFrame = pFly->GetPageFrame();
                                SwPageFrame* pPageOfAnchor = pFrame->FindPageFrame();
                                if ( pPageFrame != pPageOfAnchor )
                                {
                                    pFly->InvalidatePos();
                                    if ( pPageFrame )
                                        pPageFrame->MoveFly( pFly, pPageOfAnchor );
                                    else
                                        pPageOfAnchor->AppendFlyToPage( pFly );
                                }
                            }
                            // OD 2004-05-11 #i28701# - Because of the introduction
                            // of new positionings and alignments (e.g. aligned at
                            // page area, but anchored at-character), the position
                            // of the Writer fly frame has to be invalidated.
                            pFly->InvalidatePos();

                            // #i26945# - follow-up of #i3317#
                            // No arrangement of lowers, if Writer fly frame isn't
                            // moved
                            if ( bDirectMove &&
                                 ::lcl_ArrangeLowers( pFly,
                                                      aRectFnSet.GetPrtTop(*pFly),
                                                      bInva ) )
                            {
                                pFly->SetCompletePaint();
                            }
                        }
                        else if ( dynamic_cast< const SwAnchoredDrawObject *>( pAnchoredObj ) !=  nullptr )
                        {
                            // #i26945#
                            const SwTabFrame* pTabFrame = pLay->FindTabFrame();
                            if ( pTabFrame &&
                                 !( pTabFrame->IsFollow() &&
                                    pTabFrame->FindMaster()->IsRebuildLastLine() ) &&
                                (pAnchoredObj->GetFrameFormat().GetAnchor().GetAnchorId()
                                                                != RndStdIds::FLY_AS_CHAR))
                            {
                                SwPageFrame* pPageFrame = pAnchoredObj->GetPageFrame();
                                SwPageFrame* pPageOfAnchor = pFrame->FindPageFrame();
                                if ( pPageFrame != pPageOfAnchor )
                                {
                                    pAnchoredObj->InvalidateObjPos();
                                    if ( pPageFrame )
                                    {
                                        pPageFrame->RemoveDrawObjFromPage( *pAnchoredObj );
                                    }
                                    pPageOfAnchor->AppendDrawObjToPage( *pAnchoredObj );
                                }
                            }
                            // #i28701# - adjust last character
                            // rectangle and last top of line.
                            pAnchoredObj->AddLastCharY( lDiff );
                            pAnchoredObj->AddLastTopOfLineY( lDiff );
                            // #i52904# - re-introduce direct move
                            // of drawing objects
                            const bool bDirectMove =
                                    static_cast<const SwDrawFrameFormat&>(pAnchoredObj->GetFrameFormat()).IsPosAttrSet() &&
                                    bVertPosDepOnAnchor &&
                                    !pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos();
                            if ( bDirectMove )
                            {
                                SwObjPositioningInProgress aObjPosInProgress( *pAnchoredObj );
                                if ( aRectFnSet.IsVert() )
                                {
                                    pAnchoredObj->DrawObj()->Move( Size( lDiff, 0 ) );
                                }
                                else
                                {
                                    pAnchoredObj->DrawObj()->Move( Size( 0, lDiff ) );
                                }
                                // #i58280#
                                pAnchoredObj->InvalidateObjRectWithSpaces();
                            }
                            pAnchoredObj->InvalidateObjPos();
                        }
                        else
                        {
                            OSL_FAIL( "<lcl_ArrangeLowers(..)> - unknown type of anchored object!" );
                        }
                    }
                }
            }
            // Columns and cells are ordered horizontal, not vertical
            if( !pFrame->IsColumnFrame() && !pFrame->IsCellFrame() )
                lYStart = aRectFnSet.YInc( lYStart,
                                            aRectFnSet.GetHeight(pFrame->getFrameArea()) );

            // Nowadays, the content inside a cell can flow into the follow table.
            // Thus, the cell may only grow up to the end of the environment.
            // So the content may have grown, but the cell could not grow.
            // Therefore we have to trigger a formatting for the frames, which do
            // not fit into the cell anymore:
            SwTwips nDistanceToUpperPrtBottom =
                aRectFnSet.BottomDist( pFrame->getFrameArea(), aRectFnSet.GetPrtBottom(*pLay) );
            // #i56146# - Revise fix of issue #i26945#
            // do *not* consider content inside fly frames, if it's an undersized paragraph.
            // #i26945# - consider content inside fly frames
            if ( nDistanceToUpperPrtBottom < 0 &&
                 ( ( pFrame->IsInFly() &&
                     ( !pFrame->IsTextFrame() ||
                       !static_cast<SwTextFrame*>(pFrame)->IsUndersized() ) ) ||
                   pFrame->IsInSplitTableRow() ) )
            {
                pFrame->InvalidatePos();
            }

            pFrame = pFrame->GetNext();
        }
        return bRet;
    }

    void SwCellFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs *pAttrs )
    {
        OSL_ENSURE( pAttrs, "CellFrame::Format, pAttrs is 0." );
        const SwTabFrame* pTab = FindTabFrame();
        SwRectFnSet aRectFnSet(pTab);

        if ( !isFramePrintAreaValid() )
        {
            setFramePrintAreaValid(true);

            //Adjust position.
            if ( Lower() )
            {
                SwTwips nTopSpace, nBottomSpace, nLeftSpace, nRightSpace;
                // #i29550#
                if ( pTab->IsCollapsingBorders() && !Lower()->IsRowFrame()  )
                {
                    const SvxBoxItem& rBoxItem = pAttrs->GetBox();
                    nLeftSpace   = rBoxItem.GetDistance( SvxBoxItemLine::LEFT );
                    nRightSpace  = rBoxItem.GetDistance( SvxBoxItemLine::RIGHT );
                    nTopSpace    =  static_cast<SwRowFrame*>(GetUpper())->GetTopMarginForLowers();
                    nBottomSpace =  static_cast<SwRowFrame*>(GetUpper())->GetBottomMarginForLowers();
                }
                else
                {
                    // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
                    nLeftSpace   = pAttrs->CalcLeft( this );
                    nRightSpace  = pAttrs->CalcRight( this );
                    nTopSpace    = pAttrs->CalcTop();
                    nBottomSpace = pAttrs->CalcBottom();
                }
                aRectFnSet.SetXMargins( *this, nLeftSpace, nRightSpace );
                aRectFnSet.SetYMargins( *this, nTopSpace, nBottomSpace );
            }
        }
        // #i26945#
        long nRemaining = GetTabBox()->getRowSpan() >= 1 ?
                          ::lcl_CalcMinCellHeight( this, pTab->IsConsiderObjsForMinCellHeight(), pAttrs ) :
                          0;
        if ( !isFrameAreaSizeValid() )
        {
            setFrameAreaSizeValid(true);

            //The VarSize of the CellFrames is always the width.
            //The width is not variable though, it is defined by the format.
            //This predefined value however does not necessary match the actual
            //width. The width is calculated based on the attribute, the value in
            //the attribute matches the desired value of the TabFrame. Changes which
            //were done there are taken into account here proportionately.
            //If the cell doesn't have a neighbour anymore, it does not take the
            //attribute into account and takes the rest of the upper instead.
            SwTwips nWidth;
            if ( GetNext() )
            {
                const SwTwips nWish = pTab->GetFormat()->GetFrameSize().GetWidth();
                nWidth = pAttrs->GetSize().Width();

                OSL_ENSURE( nWish, "Table without width?" );
                OSL_ENSURE( nWidth <= nWish, "Width of cell larger than table." );
                OSL_ENSURE( nWidth > 0, "Box without width" );

                const long nPrtWidth = aRectFnSet.GetWidth(pTab->getFramePrintArea());
                if ( nWish != nPrtWidth )
                {
                    // Avoid rounding problems, at least for the new table model
                    if ( pTab->GetTable()->IsNewModel() )
                    {
                        // 1. sum of widths of cells up to this cell (in model)
                        const SwTableLine* pTabLine = GetTabBox()->GetUpper();
                        const SwTableBoxes& rBoxes = pTabLine->GetTabBoxes();
                        const SwTableBox* pTmpBox = nullptr;

                        SwTwips nSumWidth = 0;
                        size_t i = 0;
                        do
                        {
                            pTmpBox = rBoxes[ i++ ];
                            nSumWidth += pTmpBox->GetFrameFormat()->GetFrameSize().GetWidth();
                        }
                        while ( pTmpBox != GetTabBox() );

                        // 2. calculate actual width of cells up to this one
                        double nTmpWidth = nSumWidth;
                        nTmpWidth *= nPrtWidth;
                        nTmpWidth /= nWish;
                        nWidth = static_cast<SwTwips>(nTmpWidth);

                        // 3. calculate frame widths of cells up to this one:
                        const SwFrame* pTmpCell = static_cast<const SwLayoutFrame*>(GetUpper())->Lower();
                        SwTwips nSumFrameWidths = 0;
                        while ( pTmpCell != this )
                        {
                            nSumFrameWidths += aRectFnSet.GetWidth(pTmpCell->getFrameArea());
                            pTmpCell = pTmpCell->GetNext();
                        }

                        nWidth = nWidth - nSumFrameWidths;
                    }
                    else
                    {
                        // #i12092# use double instead of long,
                        // otherwise this could lead to overflows
                        double nTmpWidth = nWidth;
                        nTmpWidth *= nPrtWidth;
                        nTmpWidth /= nWish;
                        nWidth = static_cast<SwTwips>(nTmpWidth);
                    }
                }
            }
            else
            {
                OSL_ENSURE( pAttrs->GetSize().Width() > 0, "Box without width" );
                nWidth = aRectFnSet.GetWidth(GetUpper()->getFramePrintArea());
                SwFrame *pPre = GetUpper()->Lower();
                while ( pPre != this )
                {
                    nWidth -= aRectFnSet.GetWidth(pPre->getFrameArea());
                    pPre = pPre->GetNext();
                }
            }

            const long nDiff = nWidth - aRectFnSet.GetWidth(getFrameArea());

            {
                SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);

                if( IsNeighbourFrame() && IsRightToLeft() )
                {
                    aRectFnSet.SubLeft( aFrm, nDiff );
                }
                else
                {
                    aRectFnSet.AddRight( aFrm, nDiff );
                }
            }

            {
                SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
                aRectFnSet.AddRight( aPrt, nDiff );
            }

            //Adjust the height, it's defined through the content and the border.
            const long nDiffHeight = nRemaining - aRectFnSet.GetHeight(getFrameArea());
            if ( nDiffHeight )
            {
                if ( nDiffHeight > 0 )
                {
                    //Validate again if no growth happened. Invalidation is done
                    //through AdjustCells of the row.
                    if ( !Grow( nDiffHeight ) )
                    {
                        setFrameAreaSizeValid(true);
                        setFramePrintAreaValid(true);
                    }
                }
                else
                {
                    //Only keep invalidated if shrinking was done; this can be
                    //dismissed because all adjoined cells have to be the same size.
                    if ( !Shrink( -nDiffHeight ) )
                    {
                        setFrameAreaSizeValid(true);
                        setFramePrintAreaValid(true);
                    }
                }
            }
        }
        const SwFormatVertOrient &rOri = pAttrs->GetAttrSet().GetVertOrient();

        if ( !Lower() )
            return;

        // From now on, all operations are related to the table cell.
        aRectFnSet.Refresh(this);

        SwPageFrame* pPg = nullptr;
        if ( !FindTabFrame()->IsRebuildLastLine() && text::VertOrientation::NONE != rOri.GetVertOrient() &&
        // #158225# no vertical alignment of covered cells
             !IsCoveredCell() &&
             (pPg = FindPageFrame())!=nullptr )
        {
            if ( !Lower()->IsContentFrame() && !Lower()->IsSctFrame() && !Lower()->IsTabFrame() )
            {
                // OSL_ENSURE(for HTML-import!
                OSL_ENSURE( false, "VAlign to cell without content" );
                return;
            }
            bool bVertDir = true;
            // #i43913# - no vertical alignment, if wrapping
            // style influence is considered on object positioning and
            // an object is anchored inside the cell.
            const bool bConsiderWrapOnObjPos( GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) );
            //No alignment if border with flow overlaps the cell.
            if ( pPg->GetSortedObjs() )
            {
                SwRect aRect( getFramePrintArea() ); aRect += getFrameArea().Pos();
                for (SwAnchoredObject* pAnchoredObj : *pPg->GetSortedObjs())
                {
                    SwRect aTmp( pAnchoredObj->GetObjRect() );
                    const SwFrame* pAnch = pAnchoredObj->GetAnchorFrame();
                    if ( (bConsiderWrapOnObjPos && IsAnLower( pAnch )) || (!bConsiderWrapOnObjPos && aTmp.IsOver( aRect )) )
                    {
                        const SwFrameFormat& rAnchoredObjFrameFormat = pAnchoredObj->GetFrameFormat();
                        const SwFormatSurround &rSur = rAnchoredObjFrameFormat.GetSurround();

                        if ( bConsiderWrapOnObjPos || css::text::WrapTextMode_THROUGH != rSur.GetSurround() )
                        {
                            // frames, which the cell is a lower of, aren't relevant
                            if ( auto pFly = dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) )
                            {
                                if ( pFly->IsAnLower( this ) )
                                    continue;
                            }

                            // #i43913#
                            // #i52904# - no vertical alignment,
                            // if object, anchored inside cell, has temporarily
                            // consider its wrapping style on object positioning.
                            // #i58806# - no vertical alignment
                            // if object does not follow the text flow.
                            if ( bConsiderWrapOnObjPos ||
                                 !IsAnLower( pAnch ) ||
                                 pAnchoredObj->IsTmpConsiderWrapInfluence() ||
                                 !rAnchoredObjFrameFormat.GetFollowTextFlow().GetValue() )
                            {
                                bVertDir = false;
                                break;
                            }
                        }
                    }
                }
            }

            long nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
            if( ( bVertDir && ( nRemaining -= lcl_CalcTopAndBottomMargin( *this, *pAttrs ) ) < nPrtHeight ) ||
                aRectFnSet.GetTop(Lower()->getFrameArea()) != aRectFnSet.GetPrtTop(*this) )
            {
                long nDiff = aRectFnSet.GetHeight(getFramePrintArea()) - nRemaining;
                if ( nDiff >= 0 )
                {
                    long lTopOfst = 0;
                    if ( bVertDir )
                    {
                        switch ( rOri.GetVertOrient() )
                        {
                            case text::VertOrientation::CENTER:   lTopOfst = nDiff / 2; break;
                            case text::VertOrientation::BOTTOM:   lTopOfst = nDiff;     break;
                            default: break;
                        };
                    }
                    long nTmp = aRectFnSet.YInc(
                                        aRectFnSet.GetPrtTop(*this), lTopOfst );
                    if ( lcl_ArrangeLowers( this, nTmp, !bVertDir ) )
                        SetCompletePaint();
                }
            }
        }
        else
        {
            //Was an old alignment taken into account?
            if ( Lower()->IsContentFrame() )
            {
                const long lYStart = aRectFnSet.GetPrtTop(*this);
                lcl_ArrangeLowers( this, lYStart, true );
            }
        }
    }

    void SwCellFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew )
    {
        bool bAttrSetChg = pNew && RES_ATTRSET_CHG == pNew->Which();
        const SfxPoolItem *pItem = nullptr;

        if( bAttrSetChg )
            static_cast<const SwAttrSetChg*>(pNew)->GetChgSet()->GetItemState( RES_VERT_ORIENT, false, &pItem);
        else if (pNew && RES_VERT_ORIENT == pNew->Which())
            pItem = pNew;

        if ( pItem )
        {
            bool bInva = true;
            if ( text::VertOrientation::NONE == static_cast<const SwFormatVertOrient*>(pItem)->GetVertOrient() &&
                 // OD 04.11.2003 #112910#
                 Lower() && Lower()->IsContentFrame() )
            {
                SwRectFnSet aRectFnSet(this);
                const long lYStart = aRectFnSet.GetPrtTop(*this);
                bInva = lcl_ArrangeLowers( this, lYStart, false );
            }
            if ( bInva )
            {
                SetCompletePaint();
                InvalidatePrt();
            }
        }

        if ( ( bAttrSetChg && pNew &&
               SfxItemState::SET == static_cast<const SwAttrSetChg*>(pNew)->GetChgSet()->GetItemState( RES_PROTECT, false ) ) ||
             ( pNew && RES_PROTECT == pNew->Which()) )
        {
            SwViewShell *pSh = getRootFrame()->GetCurrShell();
            if( pSh && pSh->GetLayout()->IsAnyShellAccessible() )
                pSh->Imp()->InvalidateAccessibleEditableState( true, this );
        }

        if ( bAttrSetChg && pNew &&
             SfxItemState::SET == static_cast<const SwAttrSetChg*>(pNew)->GetChgSet()->GetItemState( RES_FRAMEDIR, false, &pItem ) )
        {
            SetDerivedVert( false );
            CheckDirChange();
        }

        // #i29550#
        if ( bAttrSetChg && pNew &&
             SfxItemState::SET == static_cast<const SwAttrSetChg*>(pNew)->GetChgSet()->GetItemState( RES_BOX, false, &pItem ) )
        {
            SwFrame* pTmpUpper = GetUpper();
            while ( pTmpUpper->GetUpper() && !pTmpUpper->GetUpper()->IsTabFrame() )
                pTmpUpper = pTmpUpper->GetUpper();

            SwTabFrame* pTabFrame = static_cast<SwTabFrame*>(pTmpUpper->GetUpper());
            if ( pTabFrame->IsCollapsingBorders() )
            {
                // Invalidate lowers of this and next row:
                lcl_InvalidateAllLowersPrt( static_cast<SwRowFrame*>(pTmpUpper) );
                pTmpUpper = pTmpUpper->GetNext();
                if ( pTmpUpper )
                    lcl_InvalidateAllLowersPrt( static_cast<SwRowFrame*>(pTmpUpper) );
                else
                    pTabFrame->InvalidatePrt();
            }
        }

        SwLayoutFrame::Modify( pOld, pNew );
    }

    long SwCellFrame::GetLayoutRowSpan() const
    {
        long nRet = GetTabBox()->getRowSpan();
        if ( nRet < 1 )
        {
            const SwFrame* pRow = GetUpper();
            const SwTabFrame* pTab = pRow ? static_cast<const SwTabFrame*>(pRow->GetUpper()) : nullptr;

            if ( pTab && pTab->IsFollow() && pRow == pTab->GetFirstNonHeadlineRow() )
                nRet = -nRet;
        }
        return  nRet;
    }

    void SwCellFrame::dumpAsXmlAttributes(xmlTextWriterPtr pWriter) const
    {
        SwFrame::dumpAsXmlAttributes(pWriter);
        if (SwCellFrame* pFollow = GetFollowCell())
            xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("follow"), "%" SAL_PRIuUINT32, pFollow->GetFrameId());

        if (SwCellFrame* pPrevious = GetPreviousCell())
            xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("precede"), "%" SAL_PRIuUINT32, pPrevious->GetFrameId());
    }

    // #i103961#
    void SwCellFrame::Cut()
    {
        // notification for accessibility
        {
            SwRootFrame *pRootFrame = getRootFrame();
            if( pRootFrame && pRootFrame->IsAnyShellAccessible() )
            {
                SwViewShell* pVSh = pRootFrame->GetCurrShell();
                if ( pVSh && pVSh->Imp() )
                {
                    pVSh->Imp()->DisposeAccessibleFrame( this );
                }
            }
        }

        SwLayoutFrame::Cut();
    }

    // Helper functions for repeated headlines:

    bool SwTabFrame::IsInHeadline( const SwFrame& rFrame ) const
    {
        OSL_ENSURE( IsAnLower( &rFrame ) && rFrame.IsInTab(),
                 "SwTabFrame::IsInHeadline called for frame not lower of table" );

        const SwFrame* pTmp = &rFrame;
        while ( !pTmp->GetUpper()->IsTabFrame() )
            pTmp = pTmp->GetUpper();

        return GetTable()->IsHeadline( *static_cast<const SwRowFrame*>(pTmp)->GetTabLine() );
    }

    /*
     * If this is a master table, we can may assume, that there are at least
     * nRepeat lines in the table.
     * If this is a follow table, there are intermediate states for the table
     * layout, e.g., during deletion of rows, which makes it necessary to find
     * the first non-headline row by evaluating the headline flag at the row frame.
     */
    SwRowFrame* SwTabFrame::GetFirstNonHeadlineRow() const
    {
        SwRowFrame* pRet = const_cast<SwRowFrame*>(static_cast<const SwRowFrame*>(Lower()));
        if ( pRet )
        {
            if ( IsFollow() )
            {
                while ( pRet && pRet->IsRepeatedHeadline() )
                    pRet = static_cast<SwRowFrame*>(pRet->GetNext());
            }
            else
            {
                sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat();
                while ( pRet && nRepeat > 0 )
                {
                    pRet = static_cast<SwRowFrame*>(pRet->GetNext());
                    --nRepeat;
                }
            }
        }

        return pRet;
    }

    bool SwTable::IsHeadline( const SwTableLine& rLine ) const
    {
        for ( sal_uInt16 i = 0; i < GetRowsToRepeat(); ++i )
            if ( GetTabLines()[ i ] == &rLine )
                return true;

        return false;
    }

    bool SwTabFrame::IsLayoutSplitAllowed() const
    {
        return GetFormat()->GetLayoutSplit().GetValue();
    }

    // #i29550#

    sal_uInt16 SwTabFrame::GetBottomLineSize() const
    {
        OSL_ENSURE( IsCollapsingBorders(),
                "BottomLineSize only required for collapsing borders" );

        OSL_ENSURE( Lower(), "Warning! Trying to prevent a crash" );

        const SwFrame* pTmp = GetLastLower();

        // #124755# Try to make code robust
        if ( !pTmp ) return 0;

        return static_cast<const SwRowFrame*>(pTmp)->GetBottomLineSize();
    }

    bool SwTabFrame::IsCollapsingBorders() const
    {
        return GetFormat()->GetAttrSet().Get( RES_COLLAPSING_BORDERS ).GetValue();
    }

    /// Local helper function to calculate height of first text row
    static SwTwips lcl_CalcHeightOfFirstContentLine( const SwRowFrame& rSourceLine )
    {
        // Find corresponding split line in master table
        const SwTabFrame* pTab = rSourceLine.FindTabFrame();
        SwRectFnSet aRectFnSet(pTab);
        const SwCellFrame* pCurrSourceCell = static_cast<const SwCellFrame*>(rSourceLine.Lower());

        // 1. Case: rSourceLine is a follow flow line.
        // In this case we have to return the minimum of the heights
        // of the first lines in rSourceLine.

        // 2. Case: rSourceLine is not a follow flow line.
        // In this case we have to return the maximum of the heights
        // of the first lines in rSourceLine.
        bool bIsInFollowFlowLine = rSourceLine.IsInFollowFlowRow();
        SwTwips nHeight = bIsInFollowFlowLine ? LONG_MAX : 0;

        while ( pCurrSourceCell )
        {
            // NEW TABLES
            // Skip cells which are not responsible for the height of
            // the follow flow line:
            if ( bIsInFollowFlowLine && pCurrSourceCell->GetLayoutRowSpan() > 1 )
            {
                pCurrSourceCell = static_cast<const SwCellFrame*>(pCurrSourceCell->GetNext());
                continue;
            }

            const SwFrame *pTmp = pCurrSourceCell->Lower();
            if ( pTmp )
            {
                SwTwips nTmpHeight = USHRT_MAX;
                // #i32456# Consider lower row frames
                if ( pTmp->IsRowFrame() )
                {
                    const SwRowFrame* pTmpSourceRow = static_cast<const SwRowFrame*>(pCurrSourceCell->Lower());
                    nTmpHeight = lcl_CalcHeightOfFirstContentLine( *pTmpSourceRow );
                }
                else if ( pTmp->IsTabFrame() )
                {
                    nTmpHeight = static_cast<const SwTabFrame*>(pTmp)->CalcHeightOfFirstContentLine();
                }
                else if (pTmp->IsTextFrame() || (pTmp->IsSctFrame() && pTmp->GetLower() && pTmp->GetLower()->IsTextFrame()))
                {
                    // Section frames don't influence the size/position of text
                    // frames, so 'text frame' and 'text frame in section frame' is
                    // the same case.
                    SwTextFrame* pTextFrame = nullptr;
                    if (pTmp->IsTextFrame())
                        pTextFrame = const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pTmp));
                    else
                        pTextFrame = const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pTmp->GetLower()));
                    pTextFrame->GetFormatted();
                    nTmpHeight = pTextFrame->FirstLineHeight();
                }

                if ( USHRT_MAX != nTmpHeight )
                {
                    const SwCellFrame* pPrevCell = pCurrSourceCell->GetPreviousCell();
                    if ( pPrevCell )
                    {
                        // If we are in a split row, there may be some space
                        // left in the cell frame of the master row.
                        // We look for the minimum of all first line heights;
                        SwTwips nReal = aRectFnSet.GetHeight(pPrevCell->getFramePrintArea());
                        const SwFrame* pFrame = pPrevCell->Lower();
                        const SwFrame* pLast = pFrame;
                        while ( pFrame )
                        {
                            nReal -= aRectFnSet.GetHeight(pFrame->getFrameArea());
                            pLast = pFrame;
                            pFrame = pFrame->GetNext();
                        }

                        // #i26831#, #i26520#
                        // The additional lower space of the current last.
                        // #115759# - do *not* consider the
                        // additional lower space for 'master' text frames
                        if ( pLast && pLast->IsFlowFrame() &&
                             ( !pLast->IsTextFrame() ||
                               !static_cast<const SwTextFrame*>(pLast)->GetFollow() ) )
                        {
                            nReal += SwFlowFrame::CastFlowFrame(pLast)->CalcAddLowerSpaceAsLastInTableCell();
                        }
                        // Don't forget the upper space and lower space,
                        // #115759# - do *not* consider the upper
                        // and the lower space for follow text frames.
                        if ( pTmp->IsFlowFrame() &&
                             ( !pTmp->IsTextFrame() ||
                               !static_cast<const SwTextFrame*>(pTmp)->IsFollow() ) )
                        {
                            nTmpHeight += SwFlowFrame::CastFlowFrame(pTmp)->CalcUpperSpace( nullptr, pLast);
                            nTmpHeight += SwFlowFrame::CastFlowFrame(pTmp)->CalcLowerSpace();
                        }
                        // #115759# - consider additional lower
                        // space of <pTmp>, if contains only one line.
                        // In this case it would be the new last text frame, which
                        // would have no follow and thus would add this space.
                        if ( pTmp->IsTextFrame() &&
                             const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pTmp))
                                ->GetLineCount(TextFrameIndex(COMPLETE_STRING)) == 1)
                        {
                            nTmpHeight += SwFlowFrame::CastFlowFrame(pTmp)
                                            ->CalcAddLowerSpaceAsLastInTableCell();
                        }
                        if ( nReal > 0 )
                            nTmpHeight -= nReal;
                    }
                    else
                    {
                        // pFirstRow is not a FollowFlowRow. In this case,
                        // we look for the maximum of all first line heights:
                        SwBorderAttrAccess aAccess( SwFrame::GetCache(), pCurrSourceCell );
                        const SwBorderAttrs &rAttrs = *aAccess.Get();
                        nTmpHeight += rAttrs.CalcTop() + rAttrs.CalcBottom();
                        // #i26250#
                        // Don't forget the upper space and lower space,
                        if ( pTmp->IsFlowFrame() )
                        {
                            nTmpHeight += SwFlowFrame::CastFlowFrame(pTmp)->CalcUpperSpace();
                            nTmpHeight += SwFlowFrame::CastFlowFrame(pTmp)->CalcLowerSpace();
                        }
                    }
                }

                if ( bIsInFollowFlowLine )
                {
                    // minimum
                    if ( nTmpHeight < nHeight )
                        nHeight = nTmpHeight;
                }
                else
                {
                    // maximum
                    if ( nTmpHeight > nHeight && USHRT_MAX != nTmpHeight )
                        nHeight = nTmpHeight;
                }
            }

            pCurrSourceCell = static_cast<const SwCellFrame*>(pCurrSourceCell->GetNext());
        }

        return ( LONG_MAX == nHeight ) ? 0 : nHeight;
    }

    /// Function to calculate height of first text row
    SwTwips SwTabFrame::CalcHeightOfFirstContentLine() const
    {
        SwRectFnSet aRectFnSet(this);

        const bool bDontSplit = !IsFollow() && !GetFormat()->GetLayoutSplit().GetValue();

        if ( bDontSplit )
        {
            // Table is not allowed to split: Take the whole height, that's all
            return aRectFnSet.GetHeight(getFrameArea());
        }

        SwTwips nTmpHeight = 0;

        const SwRowFrame* pFirstRow = GetFirstNonHeadlineRow();
        OSL_ENSURE( !IsFollow() || pFirstRow, "FollowTable without Lower" );

        // NEW TABLES
        if ( pFirstRow && pFirstRow->IsRowSpanLine() && pFirstRow->GetNext() )
            pFirstRow = static_cast<const SwRowFrame*>(pFirstRow->GetNext());

        // Calculate the height of the headlines:
        const sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat();
        SwTwips nRepeatHeight = nRepeat ? lcl_GetHeightOfRows( GetLower(), nRepeat ) : 0;

        // Calculate the height of the keeping lines
        // (headlines + following keeping lines):
        SwTwips nKeepHeight = nRepeatHeight;
        if ( GetFormat()->GetDoc()->GetDocumentSettingManager().get(DocumentSettingId::TABLE_ROW_KEEP) )
        {
            sal_uInt16 nKeepRows = nRepeat;

            // Check how many rows want to keep together
            while ( pFirstRow && pFirstRow->ShouldRowKeepWithNext() )
            {
                ++nKeepRows;
                pFirstRow = static_cast<const SwRowFrame*>(pFirstRow->GetNext());
            }

            if ( nKeepRows > nRepeat )
                nKeepHeight = lcl_GetHeightOfRows( GetLower(), nKeepRows );
        }

        // For master tables, the height of the headlines + the height of the
        // keeping lines (if any) has to be considered. For follow tables, we
        // only consider the height of the keeping rows without the repeated lines:
        if ( !IsFollow() )
        {
            nTmpHeight = nKeepHeight;
        }
        else
        {
            nTmpHeight = nKeepHeight - nRepeatHeight;
        }

        // pFirstRow row is the first non-heading row.
        // nTmpHeight is the height of the heading row if we are a follow.
        if ( pFirstRow )
        {
            const bool bSplittable = pFirstRow->IsRowSplitAllowed();
            const SwTwips nFirstLineHeight = aRectFnSet.GetHeight(pFirstRow->getFrameArea());

            if ( !bSplittable )
            {
                // pFirstRow is not splittable, but it is still possible that the line height of pFirstRow
                // actually is determined by a lower cell with rowspan = -1. In this case we should not
                // just return the height of the first line. Basically we need to get the height of the
                // line as it would be on the last page. Since this is quite complicated to calculate,
                // we only calculate the height of the first line.
                if ( pFirstRow->GetPrev() &&
                     static_cast<const SwRowFrame*>(pFirstRow->GetPrev())->IsRowSpanLine() )
                {
                    // Calculate maximum height of all cells with rowspan = 1:
                    SwTwips nMaxHeight = 0;
                    const SwCellFrame* pLower2 = static_cast<const SwCellFrame*>(pFirstRow->Lower());
                    while ( pLower2 )
                    {
                        if ( 1 == pLower2->GetTabBox()->getRowSpan() )
                        {
                            const SwTwips nCellHeight = lcl_CalcMinCellHeight( pLower2, true );
                            nMaxHeight = std::max( nCellHeight, nMaxHeight );
                        }
                        pLower2 = static_cast<const SwCellFrame*>(pLower2->GetNext());
                    }
                    nTmpHeight += nMaxHeight;
                }
                else
                {
                    nTmpHeight += nFirstLineHeight;
                }
            }

            // Optimization: lcl_CalcHeightOfFirstContentLine actually can trigger
            // a formatting of the row frame (via the GetFormatted()). We don't
            // want this formatting if the row does not have a height.
            else if ( 0 != nFirstLineHeight )
            {
                const bool bOldJoinLock = IsJoinLocked();
                const_cast<SwTabFrame*>(this)->LockJoin();
                const SwTwips nHeightOfFirstContentLine = lcl_CalcHeightOfFirstContentLine( *pFirstRow );

                // Consider minimum row height:
                const SwFormatFrameSize &rSz = pFirstRow->GetFormat()->GetFrameSize();

                SwTwips nMinRowHeight = 0;
                if (rSz.GetHeightSizeType() == ATT_MIN_SIZE)
                {
                    nMinRowHeight = std::max(rSz.GetHeight() - lcl_calcHeightOfRowBeforeThisFrame(*pFirstRow),
                                             0L);
                }

                nTmpHeight += std::max( nHeightOfFirstContentLine, nMinRowHeight );

                if ( !bOldJoinLock )
                    const_cast<SwTabFrame*>(this)->UnlockJoin();
            }
        }

        return nTmpHeight;
    }

    // Some more functions for covered/covering cells. This way inclusion of
    // SwCellFrame can be avoided

    bool SwFrame::IsLeaveUpperAllowed() const
    {
        const SwCellFrame* pThisCell = dynamic_cast<const SwCellFrame*>(this);
        return pThisCell && pThisCell->GetLayoutRowSpan() > 1;
    }

    bool SwFrame::IsCoveredCell() const
    {
        const SwCellFrame* pThisCell = dynamic_cast<const SwCellFrame*>(this);
        return pThisCell && pThisCell->GetLayoutRowSpan() < 1;
    }

    bool SwFrame::IsInCoveredCell() const
    {
        bool bRet = false;

        const SwFrame* pThis = this;
        while ( pThis && !pThis->IsCellFrame() )
            pThis = pThis->GetUpper();

        if ( pThis )
            bRet = pThis->IsCoveredCell();

        return bRet;
    }

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

↑ V773 Visibility scope of the 'pHeadline' pointer was exited without releasing the memory. A memory leak is possible.

↑ V773 Visibility scope of the 'pHeadline' pointer was exited without releasing the memory. A memory leak is possible.

↑ V560 A part of conditional expression is always true: pNew.

↑ V560 A part of conditional expression is always true: !bDontSplit.

↑ V560 A part of conditional expression is always true: pNew.

↑ V1019 Compound assignment expression is used inside condition.

↑ V560 A part of conditional expression is always true: nUnSplitted > 0.

↑ V560 A part of conditional expression is always true: pNew.