tdf#148620 Crash in Draw using Format > Lists > Move Down

This reverts
    commit 35f03f26799747894d1534796b6cb227bd4f233b
    speed up loading large ODS a little
since ImpEditEngine::ImpMoveParagraphs wants to manipulate
ParaPortion's and also identify them by pointer

Also convert the OSL_ASSERT in this method to an assert
to catch such problems earlier

Change-Id: Id924d00c9524223db9a96e487b331ce60e3a4fff
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133128
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/editeng/inc/editdoc.hxx b/editeng/inc/editdoc.hxx
index 4d4de94..b37fefd 100644
--- a/editeng/inc/editdoc.hxx
+++ b/editeng/inc/editdoc.hxx
@@ -433,10 +433,8 @@ class TextPortionList
    PortionsType maPortions;

public:
   TextPortionList();
    ~TextPortionList();
    TextPortionList(TextPortionList&&) = default;
    TextPortionList& operator=(TextPortionList&&) = default;
            TextPortionList();
            ~TextPortionList();

    void    Reset();
    sal_Int32 FindPortion(
@@ -477,7 +475,9 @@ private:
    bool            bInvalid:1;   // for skillful formatting

public:
    EditLine();
                    EditLine();
                    EditLine( const EditLine& );
                    ~EditLine();

    bool            IsIn( sal_Int32 nIndex ) const
                        { return ( (nIndex >= nStart ) && ( nIndex < nEnd ) ); }
@@ -532,6 +532,7 @@ public:

    EditLine*       Clone() const;

    EditLine&   operator = ( const EditLine& rLine );
    friend bool operator == ( const EditLine& r1,  const EditLine& r2  );
};

@@ -543,10 +544,8 @@ class EditLineList
    LinesType maLines;

public:
    EditLineList();
    ~EditLineList();
    EditLineList(EditLineList&&) = default;
    EditLineList& operator=(EditLineList&&) = default;
            EditLineList();
            ~EditLineList();

    void Reset();
    void DeleteFromLine(sal_Int32 nDelFrom);
@@ -583,11 +582,11 @@ private:
    bool                bVisible            : 1;    // Belongs to the node!
    bool                bForceRepaint       : 1;

                        ParaPortion( const ParaPortion& ) = delete;

public:
    ParaPortion( ContentNode* pNode );
    ~ParaPortion();
    ParaPortion( ParaPortion&& ) = default;
    ParaPortion& operator=( ParaPortion&& ) = default;
                        ParaPortion( ContentNode* pNode );
                        ~ParaPortion();

    sal_Int32 GetLineNumber( sal_Int32 nIndex ) const;

@@ -634,7 +633,7 @@ public:
class ParaPortionList
{
    mutable sal_Int32 nLastCache;
    std::vector<ParaPortion> maPortions;
    std::vector<std::unique_ptr<ParaPortion>> maPortions;
public:
                    ParaPortionList();
                    ~ParaPortionList();
@@ -647,12 +646,13 @@ public:
    ParaPortion* SafeGetObject(sal_Int32 nPos);

    sal_Int32 GetPos(const ParaPortion* p) const;
    ParaPortion& operator[](sal_Int32 nPos);
    const ParaPortion& operator[](sal_Int32 nPos) const;
    ParaPortion* operator[](sal_Int32 nPos);
    const ParaPortion* operator[](sal_Int32 nPos) const;

    ParaPortion Remove(sal_Int32 nPos);
    ParaPortion& Insert(sal_Int32 nPos, ParaPortion&& p);
    void Append(ParaPortion&& p);
    std::unique_ptr<ParaPortion> Release(sal_Int32 nPos);
    void Remove(sal_Int32 nPos);
    void Insert(sal_Int32 nPos, std::unique_ptr<ParaPortion> p);
    void Append(std::unique_ptr<ParaPortion> p);
    sal_Int32 Count() const;

#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
diff --git a/editeng/qa/unit/core-test.cxx b/editeng/qa/unit/core-test.cxx
index ffdec6f..8965b8c 100644
--- a/editeng/qa/unit/core-test.cxx
+++ b/editeng/qa/unit/core-test.cxx
@@ -194,8 +194,8 @@ void Test::testLineSpacing()
        aEditEngine.QuickSetAttribs(*pSet, aSelection);

        // Assert changes
        ParaPortion& rParaPortion = aEditEngine.GetParaPortions()[0];
        ContentNode* const pNode = rParaPortion.GetNode();
        ParaPortion* pParaPortion = aEditEngine.GetParaPortions()[0];
        ContentNode* const pNode = pParaPortion->GetNode();
        const SvxLineSpacingItem& rLSItem = pNode->GetContentAttribs().GetItem(EE_PARA_SBL);
        CPPUNIT_ASSERT_EQUAL(SvxInterLineSpaceRule::Prop, rLSItem.GetInterLineSpaceRule());
        CPPUNIT_ASSERT_EQUAL(nSpace, rLSItem.GetPropLineSpace());
diff --git a/editeng/source/editeng/editdbg.cxx b/editeng/source/editeng/editdbg.cxx
index 89bff9f..e3c8f5a 100644
--- a/editeng/source/editeng/editdbg.cxx
+++ b/editeng/source/editeng/editdbg.cxx
@@ -335,22 +335,22 @@ void EditEngine::DumpData(const EditEngine* pEE, bool bInfoBox)
    fprintf( fp, "\n================================================================================" );
    for ( sal_Int32 nPortion = 0; nPortion < pEE->pImpEditEngine->GetParaPortions().Count(); nPortion++)
    {
        ParaPortion& rPPortion = pEE->pImpEditEngine->GetParaPortions()[nPortion];
        ParaPortion* pPPortion = pEE->pImpEditEngine->GetParaPortions()[nPortion];
        fprintf( fp, "\nParagraph %" SAL_PRIdINT32 ": Length = %" SAL_PRIdINT32 ", Invalid = %i\nText = '%s'",
                 nPortion, rPPortion.GetNode()->Len(), rPPortion.IsInvalid(),
                 OUStringToOString(rPPortion.GetNode()->GetString(), RTL_TEXTENCODING_UTF8).getStr() );
                 nPortion, pPPortion->GetNode()->Len(), pPPortion->IsInvalid(),
                 OUStringToOString(pPPortion->GetNode()->GetString(), RTL_TEXTENCODING_UTF8).getStr() );
        fprintf( fp, "\nVorlage:" );
        SfxStyleSheet* pStyle = rPPortion.GetNode()->GetStyleSheet();
        SfxStyleSheet* pStyle = pPPortion->GetNode()->GetStyleSheet();
        if ( pStyle )
            fprintf( fp, " %s", OUStringToOString( pStyle->GetName(), RTL_TEXTENCODING_UTF8).getStr() );
        fprintf( fp, "\nParagraph attribute:" );
        DbgOutItemSet( fp, rPPortion.GetNode()->GetContentAttribs().GetItems(), false, false );
        DbgOutItemSet( fp, pPPortion->GetNode()->GetContentAttribs().GetItems(), false, false );

        fprintf( fp, "\nCharacter attribute:" );
        bool bZeroAttr = false;
        for ( sal_Int32 z = 0; z < rPPortion.GetNode()->GetCharAttribs().Count(); ++z )
        for ( sal_Int32 z = 0; z < pPPortion->GetNode()->GetCharAttribs().Count(); ++z )
        {
            const std::unique_ptr<EditCharAttrib>& rAttr = rPPortion.GetNode()->GetCharAttribs().GetAttribs()[z];
            const std::unique_ptr<EditCharAttrib>& rAttr = pPPortion->GetNode()->GetCharAttribs().GetAttribs()[z];
            OStringBuffer aCharAttribs;
            aCharAttribs.append("\nA");
            aCharAttribs.append(nPortion);
@@ -370,20 +370,20 @@ void EditEngine::DumpData(const EditEngine* pEE, bool bInfoBox)
        if ( bZeroAttr )
            fprintf( fp, "\nNULL-Attribute!" );

        const sal_Int32 nTextPortions = rPPortion.GetTextPortions().Count();
        const sal_Int32 nTextPortions = pPPortion->GetTextPortions().Count();
        OStringBuffer aPortionStr("\nText portions: #");
        aPortionStr.append(nTextPortions);
        aPortionStr.append(" \nA");
        aPortionStr.append(nPortion);
        aPortionStr.append(": Paragraph Length = ");
        aPortionStr.append(rPPortion.GetNode()->Len());
        aPortionStr.append(pPPortion->GetNode()->Len());
        aPortionStr.append("\nA");
        aPortionStr.append(nPortion);
        aPortionStr.append(": ");
        sal_Int32 n = 0;
        for ( sal_Int32 z = 0; z < nTextPortions; ++z )
        {
            TextPortion& rPortion = rPPortion.GetTextPortions()[z];
            TextPortion& rPortion = pPPortion->GetTextPortions()[z];
            aPortionStr.append(' ');
            aPortionStr.append(rPortion.GetLen());
            aPortionStr.append('(');
@@ -399,23 +399,23 @@ void EditEngine::DumpData(const EditEngine* pEE, bool bInfoBox)
        aPortionStr.append(nPortion);
        aPortionStr.append(": Total length: ");
        aPortionStr.append(n);
        if ( rPPortion.GetNode()->Len() != n )
        if ( pPPortion->GetNode()->Len() != n )
            aPortionStr.append(" => Error !!!");
        fprintf(fp, "%s", aPortionStr.getStr());

        fprintf( fp, "\n\nLines:" );
        // First the content ...
        for ( sal_Int32 nLine = 0; nLine < rPPortion.GetLines().Count(); nLine++ )
        for ( sal_Int32 nLine = 0; nLine < pPPortion->GetLines().Count(); nLine++ )
        {
            EditLine& rLine = rPPortion.GetLines()[nLine];
            EditLine& rLine = pPPortion->GetLines()[nLine];

            OString aLine(OUStringToOString(rPPortion.GetNode()->Copy(rLine.GetStart(), rLine.GetEnd() - rLine.GetStart()), RTL_TEXTENCODING_ASCII_US));
            OString aLine(OUStringToOString(pPPortion->GetNode()->Copy(rLine.GetStart(), rLine.GetEnd() - rLine.GetStart()), RTL_TEXTENCODING_ASCII_US));
            fprintf( fp, "\nLine %" SAL_PRIdINT32 "\t>%s<", nLine, aLine.getStr() );
        }
        // then the internal data ...
        for ( sal_Int32 nLine = 0; nLine < rPPortion.GetLines().Count(); nLine++ )
        for ( sal_Int32 nLine = 0; nLine < pPPortion->GetLines().Count(); nLine++ )
        {
            EditLine& rLine = rPPortion.GetLines()[nLine];
            EditLine& rLine = pPPortion->GetLines()[nLine];
            fprintf( fp, "\nLine %" SAL_PRIdINT32 ":\tStart: %" SAL_PRIdINT32 ",\tEnd: %" SAL_PRIdINT32, nLine, rLine.GetStart(), rLine.GetEnd() );
            fprintf( fp, "\t\tPortions: %" SAL_PRIdINT32 " - %" SAL_PRIdINT32 ".\tHight: %i, Ascent=%i", rLine.GetStartPortion(), rLine.GetEndPortion(), rLine.GetHeight(), rLine.GetMaxAscent() );
        }
diff --git a/editeng/source/editeng/editdoc.cxx b/editeng/source/editeng/editdoc.cxx
index 36a7d57..3aa587b 100644
--- a/editeng/source/editeng/editdoc.cxx
+++ b/editeng/source/editeng/editdoc.cxx
@@ -369,6 +369,7 @@ TextPortionList::TextPortionList()

TextPortionList::~TextPortionList()
{
    Reset();
}

void TextPortionList::Reset()
@@ -683,65 +684,52 @@ ParaPortionList::~ParaPortionList()

sal_Int32 ParaPortionList::GetPos(const ParaPortion* p) const
{
    sal_Int32 nArrayLen = maPortions.size();
    return FastGetPos(maPortions, p, nLastCache);
}

    // Through certain filter code-paths we do a lot of appends, which in
    // turn call GetPos - creating some N^2 nightmares. If we have a
    // non-trivially large list, do a few checks from the end first.
    if (nLastCache > 16 && nArrayLen > 16)
ParaPortion* ParaPortionList::operator [](sal_Int32 nPos)
{
    return 0 <= nPos && nPos < static_cast<sal_Int32>(maPortions.size()) ? maPortions[nPos].get() : nullptr;
}

const ParaPortion* ParaPortionList::operator [](sal_Int32 nPos) const
{
    return 0 <= nPos && nPos < static_cast<sal_Int32>(maPortions.size()) ? maPortions[nPos].get() : nullptr;
}

std::unique_ptr<ParaPortion> ParaPortionList::Release(sal_Int32 nPos)
{
    if (nPos < 0 || static_cast<sal_Int32>(maPortions.size()) <= nPos)
    {
        sal_Int32 nEnd;
        if (nLastCache > nArrayLen - 2)
            nEnd = nArrayLen;
        else
            nEnd = nLastCache + 2;

        for (sal_Int32 nIdx = nLastCache - 2; nIdx < nEnd; ++nIdx)
        {
            if (&maPortions.at(nIdx) == p)
            {
                nLastCache = nIdx;
                return nIdx;
            }
        }
        SAL_WARN( "editeng", "ParaPortionList::Release - out of bounds pos " << nPos);
        return nullptr;
    }
    // The world's lamest linear search from svarray...
    for (sal_Int32 nIdx = 0; nIdx < nArrayLen; ++nIdx)
        if (&maPortions.at(nIdx) == p)
        {
            nLastCache = nIdx;
            return nLastCache;
        }

    // XXX "not found" condition for sal_Int32 indexes
    return EE_PARA_NOT_FOUND;
    std::unique_ptr<ParaPortion> p = std::move(maPortions[nPos]);
    maPortions.erase(maPortions.begin()+nPos);
    return p;
}

ParaPortion& ParaPortionList::operator [](sal_Int32 nPos)
void ParaPortionList::Remove(sal_Int32 nPos)
{
    return maPortions[nPos];
    if (nPos < 0 || static_cast<sal_Int32>(maPortions.size()) <= nPos)
    {
        SAL_WARN( "editeng", "ParaPortionList::Remove - out of bounds pos " << nPos);
        return;
    }
    maPortions.erase(maPortions.begin()+nPos);
}

const ParaPortion& ParaPortionList::operator [](sal_Int32 nPos) const
void ParaPortionList::Insert(sal_Int32 nPos, std::unique_ptr<ParaPortion> p)
{
    return maPortions[nPos];
}

ParaPortion ParaPortionList::Remove(sal_Int32 nPos)
{
    auto it = maPortions.begin()+nPos;
    ParaPortion val = std::move(*it);
    maPortions.erase(it);
    return val;
}

ParaPortion& ParaPortionList::Insert(sal_Int32 nPos, ParaPortion&& p)
{
    if (nPos < 0 || static_cast<sal_Int32>(maPortions.size()) < nPos)
    {
        SAL_WARN( "editeng", "ParaPortionList::Insert - out of bounds pos " << nPos);
        return;
    }
    maPortions.insert(maPortions.begin()+nPos, std::move(p));
    return maPortions[nPos];
}

void ParaPortionList::Append(ParaPortion&& p)
void ParaPortionList::Append(std::unique_ptr<ParaPortion> p)
{
    maPortions.push_back(std::move(p));
}
@@ -767,9 +755,10 @@ tools::Long ParaPortionList::GetYOffset(const ParaPortion* pPPortion) const
    tools::Long nHeight = 0;
    for (const auto & rPortion : maPortions)
    {
        if ( pPPortion == &rPortion )
        const ParaPortion* pTmpPortion = rPortion.get();
        if ( pTmpPortion == pPPortion )
            return nHeight;
        nHeight += rPortion.GetHeight();
        nHeight += pTmpPortion->GetHeight();
    }
    OSL_FAIL( "GetYOffset: Portion not found" );
    return nHeight;
@@ -780,7 +769,7 @@ sal_Int32 ParaPortionList::FindParagraph(tools::Long nYOffset) const
    tools::Long nY = 0;
    for (size_t i = 0, n = maPortions.size(); i < n; ++i)
    {
        nY += maPortions[i].GetHeight(); // should also be correct even in bVisible!
        nY += maPortions[i]->GetHeight(); // should also be correct even in bVisible!
        if ( nY > nYOffset )
            return i <= SAL_MAX_INT32 ? static_cast<sal_Int32>(i) : SAL_MAX_INT32;
    }
@@ -789,12 +778,12 @@ sal_Int32 ParaPortionList::FindParagraph(tools::Long nYOffset) const

const ParaPortion* ParaPortionList::SafeGetObject(sal_Int32 nPos) const
{
    return 0 <= nPos && nPos < static_cast<sal_Int32>(maPortions.size()) ? &maPortions[nPos] : nullptr;
    return 0 <= nPos && nPos < static_cast<sal_Int32>(maPortions.size()) ? maPortions[nPos].get() : nullptr;
}

ParaPortion* ParaPortionList::SafeGetObject(sal_Int32 nPos)
{
    return 0 <= nPos && nPos < static_cast<sal_Int32>(maPortions.size()) ? &maPortions[nPos] : nullptr;
    return 0 <= nPos && nPos < static_cast<sal_Int32>(maPortions.size()) ? maPortions[nPos].get() : nullptr;
}

#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
@@ -938,6 +927,26 @@ EditLine::EditLine() :
{
}

EditLine::EditLine( const EditLine& r ) :
    nTxtWidth(0),
    nStartPosX(0),
    nStart(r.nStart),
    nEnd(r.nEnd),
    nStartPortion(r.nStartPortion),
    nEndPortion(r.nEndPortion),
    nHeight(0),
    nTxtHeight(0),
    nMaxAscent(0),
    bHangingPunctuation(r.bHangingPunctuation),
    bInvalid(true)
{
}

EditLine::~EditLine()
{
}


EditLine* EditLine::Clone() const
{
    EditLine* pL = new EditLine;
@@ -972,6 +981,15 @@ bool operator == ( const EditLine& r1,  const EditLine& r2  )
    return true;
}

EditLine& EditLine::operator = ( const EditLine& r )
{
    nEnd = r.nEnd;
    nStart = r.nStart;
    nEndPortion = r.nEndPortion;
    nStartPortion = r.nStartPortion;
    return *this;
}


void EditLine::SetHeight( sal_uInt16 nH, sal_uInt16 nTxtH )
{
diff --git a/editeng/source/editeng/editeng.cxx b/editeng/source/editeng/editeng.cxx
index 237c782..4e87300 100644
--- a/editeng/source/editeng/editeng.cxx
+++ b/editeng/source/editeng/editeng.cxx
@@ -694,12 +694,12 @@ bool EditEngine::IsIdleFormatterActive() const

ParaPortion* EditEngine::FindParaPortion(ContentNode const * pNode)
{
    return &pImpEditEngine->FindParaPortion(pNode);
    return pImpEditEngine->FindParaPortion(pNode);
}

const ParaPortion* EditEngine::FindParaPortion(ContentNode const * pNode) const
{
    return &pImpEditEngine->FindParaPortion(pNode);
    return pImpEditEngine->FindParaPortion(pNode);
}

const ParaPortion* EditEngine::GetPrevVisPortion(const ParaPortion* pCurPortion) const
@@ -1926,7 +1926,7 @@ void EditEngine::SetControlWord( EEControlBits nWord )
        for ( sal_Int32 n = 0; n < nNodes; n++ )
        {
            ContentNode* pNode = pImpEditEngine->GetEditDoc().GetObject( n );
            const ParaPortion& rPortion = pImpEditEngine->GetParaPortions()[n];
            const ParaPortion* pPortion = pImpEditEngine->GetParaPortions()[n];
            bool bWrongs = false;
            if (pNode->GetWrongList() != nullptr)
                bWrongs = !pNode->GetWrongList()->empty();
@@ -1936,10 +1936,10 @@ void EditEngine::SetControlWord( EEControlBits nWord )
                pImpEditEngine->aInvalidRect.SetLeft( 0 );
                pImpEditEngine->aInvalidRect.SetRight( pImpEditEngine->GetPaperSize().Width() );
                pImpEditEngine->aInvalidRect.SetTop( nY+1 );
                pImpEditEngine->aInvalidRect.SetBottom( nY + rPortion.GetHeight()-1 );
                pImpEditEngine->aInvalidRect.SetBottom( nY+pPortion->GetHeight()-1 );
                pImpEditEngine->UpdateViews( pImpEditEngine->pActiveView );
            }
            nY += rPortion.GetHeight();
            nY += pPortion->GetHeight();
        }
    }
}
@@ -2281,8 +2281,8 @@ bool EditEngine::ShouldCreateBigTextObject() const
    sal_Int32 nParas = pImpEditEngine->GetEditDoc().Count();
    for ( sal_Int32 nPara = 0; nPara < nParas; nPara++  )
    {
        ParaPortion& rParaPortion = pImpEditEngine->GetParaPortions()[nPara];
        nTextPortions = nTextPortions + rParaPortion.GetTextPortions().Count();
        ParaPortion* pParaPortion = pImpEditEngine->GetParaPortions()[nPara];
        nTextPortions = nTextPortions + pParaPortion->GetTextPortions().Count();
    }
    return nTextPortions >= pImpEditEngine->GetBigTextObjectStart();
}
@@ -2439,11 +2439,11 @@ ParagraphInfos EditEngine::GetParagraphInfos( sal_Int32 nPara )
    aInfos.bValid = pImpEditEngine->IsFormatted();
    if ( pImpEditEngine->IsFormatted() )
    {
        const ParaPortion& rParaPortion = pImpEditEngine->GetParaPortions()[nPara];
        const EditLine* pLine = rParaPortion.GetLines().Count() ?
                &rParaPortion.GetLines()[0] : nullptr;
        DBG_ASSERT( pLine, "GetParagraphInfos - Paragraph out of range" );
        if ( pLine )
        const ParaPortion* pParaPortion = pImpEditEngine->GetParaPortions()[nPara];
        const EditLine* pLine = (pParaPortion && pParaPortion->GetLines().Count()) ?
                &pParaPortion->GetLines()[0] : nullptr;
        DBG_ASSERT( pParaPortion && pLine, "GetParagraphInfos - Paragraph out of range" );
        if ( pParaPortion && pLine )
        {
            aInfos.nFirstLineHeight = pLine->GetHeight();
            aInfos.nFirstLineTextHeight = pLine->GetTxtHeight();
diff --git a/editeng/source/editeng/impedit.cxx b/editeng/source/editeng/impedit.cxx
index cfd6eb5..d43e305 100644
--- a/editeng/source/editeng/impedit.cxx
+++ b/editeng/source/editeng/impedit.cxx
@@ -1155,7 +1155,7 @@ tools::Rectangle ImpEditView::GetEditCursor() const
    if (nPara == EE_PARA_NOT_FOUND) // #i94322
        return tools::Rectangle();

    const ParaPortion& rParaPortion = pEditEngine->GetParaPortions()[nPara];
    const ParaPortion* pParaPortion = pEditEngine->GetParaPortions()[nPara];

    GetCursorFlags nShowCursorFlags = nExtraCursorFlags | GetCursorFlags::TextOnly;

@@ -1168,7 +1168,7 @@ tools::Rectangle ImpEditView::GetEditCursor() const
        nShowCursorFlags |= GetCursorFlags::PreferPortionStart;
    }

    return ImplGetEditCursor(aPaM, nShowCursorFlags, nTextPortionStart, &rParaPortion);
    return ImplGetEditCursor(aPaM, nShowCursorFlags, nTextPortionStart, pParaPortion);
}

void ImpEditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor )
@@ -1202,7 +1202,7 @@ void ImpEditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor )
    if (nPara == EE_PARA_NOT_FOUND) // #i94322
        return;

    const ParaPortion& rParaPortion = pEditEngine->GetParaPortions()[nPara];
    const ParaPortion* pParaPortion = pEditEngine->GetParaPortions()[nPara];

    GetCursorFlags nShowCursorFlags = nExtraCursorFlags | GetCursorFlags::TextOnly;

@@ -1215,7 +1215,7 @@ void ImpEditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor )
        nShowCursorFlags |= GetCursorFlags::PreferPortionStart;
    }

    tools::Rectangle aEditCursor = ImplGetEditCursor(aPaM, nShowCursorFlags, nTextPortionStart, &rParaPortion);
    tools::Rectangle aEditCursor = ImplGetEditCursor(aPaM, nShowCursorFlags, nTextPortionStart, pParaPortion);

    if ( bGotoCursor  ) // && (!pEditEngine->pImpEditEngine->GetStatus().AutoPageSize() ) )
    {
@@ -1464,8 +1464,8 @@ void ImpEditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor )
        CursorDirection nCursorDir = CursorDirection::NONE;
        if ( IsInsertMode() && !aEditSelection.HasRange() && ( pEditEngine->pImpEditEngine->HasDifferentRTLLevels( aPaM.GetNode() ) ) )
        {
            sal_uInt16 nTextPortion = rParaPortion.GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, bool(nShowCursorFlags & GetCursorFlags::PreferPortionStart) );
            const TextPortion& rTextPortion = rParaPortion.GetTextPortions()[nTextPortion];
            sal_uInt16 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, bool(nShowCursorFlags & GetCursorFlags::PreferPortionStart) );
            const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[nTextPortion];
            if (rTextPortion.IsRightToLeft())
                nCursorDir = CursorDirection::RTL;
            else
@@ -1896,8 +1896,8 @@ bool ImpEditView::IsBulletArea( const Point& rPos, sal_Int32* pPara )
        sal_Int32 nPara = pEditEngine->GetEditDoc().GetPos( aPaM.GetNode() );
        tools::Rectangle aBulletArea = pEditEngine->GetBulletArea( nPara );
        tools::Long nY = pEditEngine->GetDocPosTopLeft( nPara ).Y();
        const ParaPortion& rParaPortion = pEditEngine->GetParaPortions()[nPara];
        nY += rParaPortion.GetFirstLineOffset();
        const ParaPortion* pParaPortion = pEditEngine->GetParaPortions()[nPara];
        nY += pParaPortion->GetFirstLineOffset();
        if ( ( aDocPos.Y() > ( nY + aBulletArea.Top() ) ) &&
             ( aDocPos.Y() < ( nY + aBulletArea.Bottom() ) ) &&
             ( aDocPos.X() > ( aBulletArea.Left() ) ) &&
diff --git a/editeng/source/editeng/impedit.hxx b/editeng/source/editeng/impedit.hxx
index e66988d..4a0134b 100644
--- a/editeng/source/editeng/impedit.hxx
+++ b/editeng/source/editeng/impedit.hxx
@@ -765,8 +765,8 @@ private:

    void                CheckIdleFormatter();

    inline const ParaPortion& FindParaPortion( const ContentNode* pNode ) const;
    inline ParaPortion& FindParaPortion( ContentNode const * pNode );
    inline const ParaPortion* FindParaPortion( const ContentNode* pNode ) const;
    inline ParaPortion* FindParaPortion( ContentNode const * pNode );

    css::uno::Reference< css::datatransfer::XTransferable > CreateTransferable( const EditSelection& rSelection );

@@ -1267,14 +1267,14 @@ inline SfxUndoManager* ImpEditEngine::SetUndoManager(SfxUndoManager* pNew)
    return pRetval;
}

inline const ParaPortion& ImpEditEngine::FindParaPortion( const ContentNode* pNode ) const
inline const ParaPortion* ImpEditEngine::FindParaPortion( const ContentNode* pNode ) const
{
    sal_Int32 nPos = aEditDoc.GetPos( pNode );
    DBG_ASSERT( nPos < GetParaPortions().Count(), "Portionloser Node?" );
    return GetParaPortions()[ nPos ];
}

inline ParaPortion& ImpEditEngine::FindParaPortion( ContentNode const * pNode )
inline ParaPortion* ImpEditEngine::FindParaPortion( ContentNode const * pNode )
{
    sal_Int32 nPos = aEditDoc.GetPos( pNode );
    DBG_ASSERT( nPos < GetParaPortions().Count(), "Portionloser Node?" );
diff --git a/editeng/source/editeng/impedit2.cxx b/editeng/source/editeng/impedit2.cxx
index 94cc2d47..2f44eaf 100644
--- a/editeng/source/editeng/impedit2.cxx
+++ b/editeng/source/editeng/impedit2.cxx
@@ -239,7 +239,7 @@ void ImpEditEngine::InitDoc(bool bKeepParaAttribs)

    GetParaPortions().Reset();

    GetParaPortions().Insert(0, ParaPortion( aEditDoc[0] ));
    GetParaPortions().Insert(0, std::make_unique<ParaPortion>( aEditDoc[0] ));

    bFormatted = false;

@@ -379,8 +379,8 @@ bool ImpEditEngine::Command( const CommandEvent& rCEvt, EditView* pView )
                }
            }

            ParaPortion& rPortion = FindParaPortion( mpIMEInfos->aPos.GetNode() );
            rPortion.MarkSelectionInvalid( mpIMEInfos->aPos.GetIndex() );
            ParaPortion* pPortion = FindParaPortion( mpIMEInfos->aPos.GetNode() );
            pPortion->MarkSelectionInvalid( mpIMEInfos->aPos.GetIndex() );

            bool bWasCursorOverwrite = mpIMEInfos->bWasCursorOverwrite;

@@ -445,8 +445,8 @@ bool ImpEditEngine::Command( const CommandEvent& rCEvt, EditView* pView )
                    mpIMEInfos->nLen = pData->GetText().getLength();
                }

                ParaPortion& rPortion = FindParaPortion( mpIMEInfos->aPos.GetNode() );
                rPortion.MarkSelectionInvalid( mpIMEInfos->aPos.GetIndex() );
                ParaPortion* pPortion = FindParaPortion( mpIMEInfos->aPos.GetNode() );
                pPortion->MarkSelectionInvalid( mpIMEInfos->aPos.GetIndex() );
                FormatAndLayout( pView );
            }

@@ -772,8 +772,9 @@ void ImpEditEngine::ParaAttribsChanged( ContentNode const * pNode, bool bIgnoreU
    aEditDoc.SetModified( true );
    bFormatted = false;

    ParaPortion& rPortion = FindParaPortion( pNode );
    rPortion.MarkSelectionInvalid( 0 );
    ParaPortion* pPortion = FindParaPortion( pNode );
    OSL_ENSURE( pPortion, "ParaAttribsChanged: Portion?" );
    pPortion->MarkSelectionInvalid( 0 );

    sal_Int32 nPara = aEditDoc.GetPos( pNode );
    if ( bIgnoreUndoCheck || pEditEngine->IsInUndo() )
@@ -1258,14 +1259,15 @@ EditPaM ImpEditEngine::CursorUp( const EditPaM& rPaM, EditView const * pView )
{
    assert(pView && "No View - No Cursor Movement!");

    const ParaPortion& rPPortion = FindParaPortion( rPaM.GetNode() );
    sal_Int32 nLine = rPPortion.GetLineNumber( rPaM.GetIndex() );
    const EditLine& rLine = rPPortion.GetLines()[nLine];
    const ParaPortion* pPPortion = FindParaPortion( rPaM.GetNode() );
    OSL_ENSURE( pPPortion, "No matching portion found: CursorUp ");
    sal_Int32 nLine = pPPortion->GetLineNumber( rPaM.GetIndex() );
    const EditLine& rLine = pPPortion->GetLines()[nLine];

    tools::Long nX;
    if ( pView->pImpEditView->nTravelXPos == TRAVEL_X_DONTKNOW )
    {
        nX = GetXPos( &rPPortion, &rLine, rPaM.GetIndex() );
        nX = GetXPos( pPPortion, &rLine, rPaM.GetIndex() );
        pView->pImpEditView->nTravelXPos = nX+nOnePixelInRef;
    }
    else
@@ -1274,8 +1276,8 @@ EditPaM ImpEditEngine::CursorUp( const EditPaM& rPaM, EditView const * pView )
    EditPaM aNewPaM( rPaM );
    if ( nLine )    // same paragraph
    {
        const EditLine& rPrevLine = rPPortion.GetLines()[nLine-1];
        aNewPaM.SetIndex( GetChar( &rPPortion, &rPrevLine, nX ) );
        const EditLine& rPrevLine = pPPortion->GetLines()[nLine-1];
        aNewPaM.SetIndex( GetChar( pPPortion, &rPrevLine, nX ) );
        // If a previous automatically wrapped line, and one has to be exactly
        // at the end of this line, the cursor lands on the current line at the
        // beginning. See Problem: Last character of an automatically wrapped
@@ -1285,7 +1287,7 @@ EditPaM ImpEditEngine::CursorUp( const EditPaM& rPaM, EditView const * pView )
    }
    else    // previous paragraph
    {
        const ParaPortion* pPrevPortion = GetPrevVisPortion( &rPPortion );
        const ParaPortion* pPrevPortion = GetPrevVisPortion( pPPortion );
        if ( pPrevPortion )
        {
            const EditLine& rLine2 = pPrevPortion->GetLines()[pPrevPortion->GetLines().Count()-1];
@@ -1301,31 +1303,32 @@ EditPaM ImpEditEngine::CursorDown( const EditPaM& rPaM, EditView const * pView )
{
    OSL_ENSURE( pView, "No View - No Cursor Movement!" );

    const ParaPortion& rPPortion = FindParaPortion( rPaM.GetNode() );
    sal_Int32 nLine = rPPortion.GetLineNumber( rPaM.GetIndex() );
    const ParaPortion* pPPortion = FindParaPortion( rPaM.GetNode() );
    OSL_ENSURE( pPPortion, "No matching portion found: CursorDown" );
    sal_Int32 nLine = pPPortion->GetLineNumber( rPaM.GetIndex() );

    tools::Long nX;
    if ( pView->pImpEditView->nTravelXPos == TRAVEL_X_DONTKNOW )
    {
        const EditLine& rLine = rPPortion.GetLines()[nLine];
        nX = GetXPos( &rPPortion, &rLine, rPaM.GetIndex() );
        const EditLine& rLine = pPPortion->GetLines()[nLine];
        nX = GetXPos( pPPortion, &rLine, rPaM.GetIndex() );
        pView->pImpEditView->nTravelXPos = nX+nOnePixelInRef;
    }
    else
        nX = pView->pImpEditView->nTravelXPos;

    EditPaM aNewPaM( rPaM );
    if ( nLine < rPPortion.GetLines().Count()-1 )
    if ( nLine < pPPortion->GetLines().Count()-1 )
    {
        const EditLine& rNextLine = rPPortion.GetLines()[nLine+1];
        aNewPaM.SetIndex( GetChar( &rPPortion, &rNextLine, nX ) );
        const EditLine& rNextLine = pPPortion->GetLines()[nLine+1];
        aNewPaM.SetIndex( GetChar( pPPortion, &rNextLine, nX ) );
        // Special treatment, see CursorUp ...
        if ( ( aNewPaM.GetIndex() == rNextLine.GetEnd() ) && ( aNewPaM.GetIndex() > rNextLine.GetStart() ) && ( aNewPaM.GetIndex() < rPPortion.GetNode()->Len() ) )
        if ( ( aNewPaM.GetIndex() == rNextLine.GetEnd() ) && ( aNewPaM.GetIndex() > rNextLine.GetStart() ) && ( aNewPaM.GetIndex() < pPPortion->GetNode()->Len() ) )
            aNewPaM = CursorLeft( aNewPaM );
    }
    else    // next paragraph
    {
        const ParaPortion* pNextPortion = GetNextVisPortion( &rPPortion );
        const ParaPortion* pNextPortion = GetNextVisPortion( pPPortion );
        if ( pNextPortion )
        {
            const EditLine& rLine = pNextPortion->GetLines()[0];
@@ -1343,9 +1346,10 @@ EditPaM ImpEditEngine::CursorDown( const EditPaM& rPaM, EditView const * pView )

EditPaM ImpEditEngine::CursorStartOfLine( const EditPaM& rPaM )
{
    const ParaPortion& rCurPortion = FindParaPortion( rPaM.GetNode() );
    sal_Int32 nLine = rCurPortion.GetLineNumber( rPaM.GetIndex() );
    const EditLine& rLine = rCurPortion.GetLines()[nLine];
    const ParaPortion* pCurPortion = FindParaPortion( rPaM.GetNode() );
    OSL_ENSURE( pCurPortion, "No Portion for the PaM ?" );
    sal_Int32 nLine = pCurPortion->GetLineNumber( rPaM.GetIndex() );
    const EditLine& rLine = pCurPortion->GetLines()[nLine];

    EditPaM aNewPaM( rPaM );
    aNewPaM.SetIndex( rLine.GetStart() );
@@ -1354,9 +1358,10 @@ EditPaM ImpEditEngine::CursorStartOfLine( const EditPaM& rPaM )

EditPaM ImpEditEngine::CursorEndOfLine( const EditPaM& rPaM )
{
    const ParaPortion& rCurPortion = FindParaPortion( rPaM.GetNode() );
    sal_Int32 nLine = rCurPortion.GetLineNumber( rPaM.GetIndex() );
    const EditLine& rLine = rCurPortion.GetLines()[nLine];
    const ParaPortion* pCurPortion = FindParaPortion( rPaM.GetNode() );
    OSL_ENSURE( pCurPortion, "No Portion for the PaM ?" );
    sal_Int32 nLine = pCurPortion->GetLineNumber( rPaM.GetIndex() );
    const EditLine& rLine = pCurPortion->GetLines()[nLine];

    EditPaM aNewPaM( rPaM );
    aNewPaM.SetIndex( rLine.GetEnd() );
@@ -2150,25 +2155,25 @@ EditSelection ImpEditEngine::ImpMoveParagraphs( Range aOldPositions, sal_Int32 n

    if ( nNewPos == 0 ) // Move to Start
    {
        pRecalc1 = &GetParaPortions()[0];
        pRecalc2 = &GetParaPortions()[aOldPositions.Min()];
        pRecalc1 = GetParaPortions()[0];
        pRecalc2 = GetParaPortions()[aOldPositions.Min()];

    }
    else if ( nNewPos == nParaCount )
    {
        pRecalc1 = &GetParaPortions()[nParaCount-1];
        pRecalc2 = &GetParaPortions()[aOldPositions.Max()];
        pRecalc1 = GetParaPortions()[nParaCount-1];
        pRecalc2 = GetParaPortions()[aOldPositions.Max()];
    }

    if ( aOldPositions.Min() == 0 ) // Move from Start
    {
        pRecalc3 = &GetParaPortions()[0];
        pRecalc4 = &GetParaPortions()[aOldPositions.Max()+1];
        pRecalc3 = GetParaPortions()[0];
        pRecalc4 = GetParaPortions()[aOldPositions.Max()+1];
    }
    else if ( aOldPositions.Max() == (nParaCount-1) )
    {
        pRecalc3 = &GetParaPortions()[aOldPositions.Max()];
        pRecalc4 = &GetParaPortions()[aOldPositions.Min()-1];
        pRecalc3 = GetParaPortions()[aOldPositions.Max()];
        pRecalc4 = GetParaPortions()[aOldPositions.Min()-1];
    }

    MoveParagraphsInfo aMoveParagraphsInfo( aOldPositions.Min(), aOldPositions.Max(), nNewPos );
@@ -2184,28 +2189,28 @@ EditSelection ImpEditEngine::ImpMoveParagraphs( Range aOldPositions, sal_Int32 n
    for (tools::Long i = aOldPositions.Min(); i <= aOldPositions.Max(); i++  )
    {
        // always aOldPositions.Min(), since Remove().
        ParaPortion aTmpPortion = GetParaPortions().Remove(aOldPositions.Min());
        std::unique_ptr<ParaPortion> pTmpPortion = GetParaPortions().Release(aOldPositions.Min());
        aEditDoc.Release( aOldPositions.Min() );
        aTmpPortionList.Append(std::move(aTmpPortion));
        aTmpPortionList.Append(std::move(pTmpPortion));
    }

    sal_Int32 nRealNewPos = pDestPortion ? GetParaPortions().GetPos( pDestPortion ) : GetParaPortions().Count();
    OSL_ENSURE( nRealNewPos != EE_PARA_NOT_FOUND, "ImpMoveParagraphs: Invalid Position!" );
    assert( nRealNewPos != EE_PARA_NOT_FOUND && "ImpMoveParagraphs: Invalid Position!" );

    sal_Int32 i = 0;
    while( aTmpPortionList.Count() > 0 )
    {
        ParaPortion aTmpPortion = aTmpPortionList.Remove(0);
        std::unique_ptr<ParaPortion> pTmpPortion = aTmpPortionList.Release(0);
        if ( i == 0 )
            aSelection.Min().SetNode( aTmpPortion.GetNode() );
            aSelection.Min().SetNode( pTmpPortion->GetNode() );

        aSelection.Max().SetNode( aTmpPortion.GetNode() );
        aSelection.Max().SetIndex( aTmpPortion.GetNode()->Len() );
        aSelection.Max().SetNode( pTmpPortion->GetNode() );
        aSelection.Max().SetIndex( pTmpPortion->GetNode()->Len() );

        ContentNode* pN = aTmpPortion.GetNode();
        ContentNode* pN = pTmpPortion->GetNode();
        aEditDoc.Insert(nRealNewPos+i, pN);

        GetParaPortions().Insert(nRealNewPos+i, std::move(aTmpPortion));
        GetParaPortions().Insert(nRealNewPos+i, std::move(pTmpPortion));
        ++i;
    }

@@ -2279,7 +2284,8 @@ EditPaM ImpEditEngine::ImpConnectParagraphs( ContentNode* pLeft, ContentNode* pR
    ParaAttribsChanged( pLeft, true );

    // First search for Portions since pRight is gone after ConnectParagraphs.
    ParaPortion& rLeftPortion = FindParaPortion( pLeft );
    ParaPortion* pLeftPortion = FindParaPortion( pLeft );
    OSL_ENSURE( pLeftPortion, "Blind Portion in ImpConnectParagraphs(1)" );

    if ( GetStatus().DoOnlineSpelling() )
    {
@@ -2306,7 +2312,7 @@ EditPaM ImpEditEngine::ImpConnectParagraphs( ContentNode* pLeft, ContentNode* pR
    EditPaM aPaM = aEditDoc.ConnectParagraphs( pLeft, pRight );
    GetParaPortions().Remove( nParagraphTobeDeleted );

    rLeftPortion.MarkSelectionInvalid( aPaM.GetIndex() );
    pLeftPortion->MarkSelectionInvalid( aPaM.GetIndex() );

    // the right node is deleted by EditDoc:ConnectParagraphs().
    if ( GetTextRanger() )
@@ -2316,9 +2322,9 @@ EditPaM ImpEditEngine::ImpConnectParagraphs( ContentNode* pLeft, ContentNode* pR
        // the change of the total text height too late...
        for ( sal_Int32 n = nParagraphTobeDeleted; n < GetParaPortions().Count(); n++ )
        {
            ParaPortion& rPP = GetParaPortions()[n];
            rPP.MarkSelectionInvalid( 0 );
            rPP.GetLines().Reset();
            ParaPortion* pPP = GetParaPortions()[n];
            pPP->MarkSelectionInvalid( 0 );
            pPP->GetLines().Reset();
        }
    }

@@ -2453,23 +2459,26 @@ EditPaM ImpEditEngine::ImpDeleteSelection(const EditSelection& rCurSel)
    {
        // The Rest of the StartNodes...
        ImpRemoveChars( aStartPaM, aStartPaM.GetNode()->Len() - aStartPaM.GetIndex() );
        ParaPortion& rPortion = FindParaPortion( aStartPaM.GetNode() );
        rPortion.MarkSelectionInvalid( aStartPaM.GetIndex() );
        ParaPortion* pPortion = FindParaPortion( aStartPaM.GetNode() );
        OSL_ENSURE( pPortion, "Blind Portion in ImpDeleteSelection(3)" );
        pPortion->MarkSelectionInvalid( aStartPaM.GetIndex() );

        // The beginning of the EndNodes...
        const sal_Int32 nChars = aEndPaM.GetIndex();
        aEndPaM.SetIndex( 0 );
        ImpRemoveChars( aEndPaM, nChars );
        ParaPortion& rPortion2 = FindParaPortion( aEndPaM.GetNode() );
        rPortion2.MarkSelectionInvalid( 0 );
        pPortion = FindParaPortion( aEndPaM.GetNode() );
        OSL_ENSURE( pPortion, "Blind Portion in ImpDeleteSelection(4)" );
        pPortion->MarkSelectionInvalid( 0 );
        // Join together...
        aStartPaM = ImpConnectParagraphs( aStartPaM.GetNode(), aEndPaM.GetNode() );
    }
    else
    {
        ImpRemoveChars( aStartPaM, aEndPaM.GetIndex() - aStartPaM.GetIndex() );
        ParaPortion& rPortion = FindParaPortion( aStartPaM.GetNode() );
        rPortion.MarkInvalid( aEndPaM.GetIndex(), aStartPaM.GetIndex() - aEndPaM.GetIndex() );
        ParaPortion* pPortion = FindParaPortion( aStartPaM.GetNode() );
        OSL_ENSURE( pPortion, "Blind Portion in ImpDeleteSelection(5)" );
        pPortion->MarkInvalid( aEndPaM.GetIndex(), aStartPaM.GetIndex() - aEndPaM.GetIndex() );
    }

    UpdateSelections();
@@ -2674,8 +2683,9 @@ EditPaM ImpEditEngine::InsertTextUserInput( const EditSelection& rCurSel,
        }

        aEditDoc.InsertText( aPaM, OUString(c) );
        ParaPortion& rPortion = FindParaPortion( aPaM.GetNode() );
        rPortion.MarkInvalid( aPaM.GetIndex(), 1 );
        ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() );
        OSL_ENSURE( pPortion, "Blind Portion in InsertText" );
        pPortion->MarkInvalid( aPaM.GetIndex(), 1 );
        aPaM.SetIndex( aPaM.GetIndex()+1 );   // does not do EditDoc-Method anymore
    }

@@ -2806,7 +2816,8 @@ EditPaM ImpEditEngine::ImpInsertText(const EditSelection& aCurSel, const OUStrin
                    nStart2 = nEnd2+1;
                }
            }
            ParaPortion& rPortion = FindParaPortion( aPaM.GetNode() );
            ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() );
            OSL_ENSURE( pPortion, "Blind Portion in InsertText" );

            if ( GetStatus().DoOnlineSpelling() )
            {
@@ -2815,10 +2826,10 @@ EditPaM ImpEditEngine::ImpInsertText(const EditSelection& aCurSel, const OUStrin
                if (pWrongs && !pWrongs->empty())
                    pWrongs->ClearWrongs( aCurWord.Min().GetIndex(), aPaM.GetIndex(), aPaM.GetNode() );
                // ... and mark both words as 'to be checked again'
                rPortion.MarkInvalid( aCurWord.Min().GetIndex(), aLine.getLength() );
                pPortion->MarkInvalid( aCurWord.Min().GetIndex(), aLine.getLength() );
            }
            else
                rPortion.MarkInvalid( aCurPaM.GetIndex(), aLine.getLength() );
                pPortion->MarkInvalid( aCurPaM.GetIndex(), aLine.getLength() );
        }
        if ( nEnd < aText.getLength() )
            aPaM = ImpInsertParaBreak( aPaM );
@@ -2870,8 +2881,9 @@ EditPaM ImpEditEngine::ImpInsertFeature(const EditSelection& rCurSel, const SfxP
    aPaM = aEditDoc.InsertFeature( aPaM, rItem );
    UpdateFields();

    ParaPortion& rPortion = FindParaPortion( aPaM.GetNode() );
    rPortion.MarkInvalid( aPaM.GetIndex()-1, 1 );
    ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() );
    OSL_ENSURE( pPortion, "Blind Portion in InsertFeature" );
    pPortion->MarkInvalid( aPaM.GetIndex()-1, 1 );

    TextModified();

@@ -2933,14 +2945,16 @@ EditPaM ImpEditEngine::ImpInsertParaBreak( EditPaM& rPaM, bool bKeepEndingAttrib
        pRWrongs->SetInvalidRange(0, 1);  // Only test the first word
    }

    ParaPortion& rPortion = FindParaPortion( rPaM.GetNode() );
    rPortion.MarkInvalid( rPaM.GetIndex(), 0 );
    ParaPortion* pPortion = FindParaPortion( rPaM.GetNode() );
    OSL_ENSURE( pPortion, "Blind Portion in ImpInsertParaBreak" );
    pPortion->MarkInvalid( rPaM.GetIndex(), 0 );

    // Optimization: Do not place unnecessarily many getPos to Listen!
    // Here, as in undo, but also in all other methods.
    sal_Int32 nPos = GetParaPortions().GetPos( &rPortion );
    ParaPortion& rNewPortion = GetParaPortions().Insert(nPos+1, ParaPortion(aPaM.GetNode()));
    ParaAttribsChanged( rNewPortion.GetNode() );
    sal_Int32 nPos = GetParaPortions().GetPos( pPortion );
    ParaPortion* pNewPortion = new ParaPortion( aPaM.GetNode() );
    GetParaPortions().Insert(nPos+1, std::unique_ptr<ParaPortion>(pNewPortion));
    ParaAttribsChanged( pNewPortion->GetNode() );
    if ( IsCallParaInsertedOrDeleted() )
        GetEditEnginePtr()->ParagraphInserted( nPos+1 );

@@ -2971,7 +2985,7 @@ EditPaM ImpEditEngine::ImpFastInsertParagraph( sal_Int32 nPara )

    aEditDoc.Insert(nPara, pNode);

    GetParaPortions().Insert(nPara, ParaPortion( pNode ));
    GetParaPortions().Insert(nPara, std::make_unique<ParaPortion>( pNode ));
    if ( IsCallParaInsertedOrDeleted() )
        GetEditEnginePtr()->ParagraphInserted( nPara );

@@ -3063,8 +3077,9 @@ bool ImpEditEngine::UpdateFields()
        if ( bChangesInPara )
        {
            // If possible be more precise when invalidate.
            ParaPortion& rPortion = GetParaPortions()[nPara];
            rPortion.MarkSelectionInvalid( 0 );
            ParaPortion* pPortion = GetParaPortions()[nPara];
            OSL_ENSURE( pPortion, "NULL-Pointer in Doc" );
            pPortion->MarkSelectionInvalid( 0 );
        }
    }
    return bChanges;
@@ -3168,19 +3183,19 @@ void ImpEditEngine::IterateLineAreas(const IterateLinesAreasFunc& f, IterFlag eO
    sal_Int16 nColumn = 0;
    for (sal_Int32 n = 0, nPortions = GetParaPortions().Count(); n < nPortions; ++n)
    {
        ParaPortion& rPortion = GetParaPortions()[n];
        ParaPortion* pPortion = GetParaPortions()[n];
        bool bSkipThis = true;
        if (rPortion.IsVisible())
        if (pPortion->IsVisible())
        {
            // when typing idle formatting, asynchronous Paint. Invisible Portions may be invalid.
            if (rPortion.IsInvalid())
            if (pPortion->IsInvalid())
                return;

            LineAreaInfo aInfo{
                rPortion, // rPortion
                *pPortion, // pPortion
                nullptr, // pLine
                0, // nHeightNeededToNotWrap
                { aLineStart, Size{ nColumnWidth, rPortion.GetFirstLineOffset() } }, // aArea
                { aLineStart, Size{ nColumnWidth, pPortion->GetFirstLineOffset() } }, // aArea
                n, // nPortion
                0, // nLine
                nColumn // nColumn
@@ -3194,16 +3209,16 @@ void ImpEditEngine::IterateLineAreas(const IterateLinesAreasFunc& f, IterFlag eO
            if (!aStatus.IsOutliner())
            {
                const SvxLineSpacingItem& rLSItem
                    = rPortion.GetNode()->GetContentAttribs().GetItem(EE_PARA_SBL);
                    = pPortion->GetNode()->GetContentAttribs().GetItem(EE_PARA_SBL);
                nSBL = (rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix)
                           ? GetYValue(rLSItem.GetInterLineSpace())
                           : 0;
            }

            adjustYDirectionAware(aLineStart, rPortion.GetFirstLineOffset());
            for (sal_Int32 nLine = 0, nLines = rPortion.GetLines().Count(); nLine < nLines; nLine++)
            adjustYDirectionAware(aLineStart, pPortion->GetFirstLineOffset());
            for (sal_Int32 nLine = 0, nLines = pPortion->GetLines().Count(); nLine < nLines; nLine++)
            {
                EditLine& rLine = rPortion.GetLines()[nLine];
                EditLine& rLine = pPortion->GetLines()[nLine];
                tools::Long nLineHeight = rLine.GetHeight();
                if (nLine != nLines - 1)
                    nLineHeight += nVertLineSpacing;
@@ -3239,7 +3254,7 @@ void ImpEditEngine::IterateLineAreas(const IterateLinesAreasFunc& f, IterFlag eO
            if (!aStatus.IsOutliner())
            {
                const SvxULSpaceItem& rULItem
                    = rPortion.GetNode()->GetContentAttribs().GetItem(EE_PARA_ULSPACE);
                    = pPortion->GetNode()->GetContentAttribs().GetItem(EE_PARA_ULSPACE);
                tools::Long nUL = GetYValue(rULItem.GetLower());
                adjustYDirectionAware(aLineStart, nUL);
            }
@@ -3357,19 +3372,20 @@ sal_uInt32 ImpEditEngine::CalcParaWidth( sal_Int32 nPara, bool bIgnoreExtraSpace

    // Over all the paragraphs ...

    ParaPortion& rPortion = GetParaPortions()[nPara];
    if ( rPortion.IsVisible() )
    OSL_ENSURE( 0 <= nPara && nPara < GetParaPortions().Count(), "CalcParaWidth: Out of range" );
    ParaPortion* pPortion = GetParaPortions()[nPara];
    if ( pPortion && pPortion->IsVisible() )
    {
        const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( rPortion.GetNode() );
        sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth( rPortion.GetNode() );
        const SvxLRSpaceItem& rLRItem = GetLRSpaceItem( pPortion->GetNode() );
        sal_Int32 nSpaceBeforeAndMinLabelWidth = GetSpaceBeforeAndMinLabelWidth( pPortion->GetNode() );


        // On the lines of the paragraph ...

        sal_Int32 nLines = rPortion.GetLines().Count();
        sal_Int32 nLines = pPortion->GetLines().Count();
        for ( sal_Int32 nLine = 0; nLine < nLines; nLine++ )
        {
            EditLine& rLine = rPortion.GetLines()[nLine];
            EditLine& rLine = pPortion->GetLines()[nLine];
            // nCurWidth = pLine->GetStartPosX();
            // For Center- or Right- alignment it depends on the paper
            // width, here not preferred. I general, it is best not leave it
@@ -3380,15 +3396,15 @@ sal_uInt32 ImpEditEngine::CalcParaWidth( sal_Int32 nPara, bool bIgnoreExtraSpace
            {
                tools::Long nFI = GetXValue( rLRItem.GetTextFirstLineOffset() );
                nCurWidth -= nFI;
                if ( rPortion.GetBulletX() > nCurWidth )
                if ( pPortion->GetBulletX() > nCurWidth )
                {
                    nCurWidth += nFI;   // LI?
                    if ( rPortion.GetBulletX() > nCurWidth )
                        nCurWidth = rPortion.GetBulletX();
                    if ( pPortion->GetBulletX() > nCurWidth )
                        nCurWidth = pPortion->GetBulletX();
                }
            }
            nCurWidth += GetXValue( rLRItem.GetRight() );
            nCurWidth += CalcLineWidth( &rPortion, &rLine, bIgnoreExtraSpace );
            nCurWidth += CalcLineWidth( pPortion, &rLine, bIgnoreExtraSpace );
            if ( nCurWidth > nMaxWidth )
            {
                nMaxWidth = nCurWidth;
@@ -3691,21 +3707,22 @@ void ImpEditEngine::UpdateSelections()
                {
                    nPara = GetParaPortions().Count()-1;
                }
                assert(GetParaPortions()[nPara] && "Empty Document in UpdateSelections ?");
                // Do not end up from a hidden paragraph:
                sal_Int32 nCurPara = nPara;
                sal_Int32 nLastPara = GetParaPortions().Count()-1;
                while ( nPara <= nLastPara && !GetParaPortions()[nPara].IsVisible() )
                while ( nPara <= nLastPara && !GetParaPortions()[nPara]->IsVisible() )
                    nPara++;
                if ( nPara > nLastPara ) // then also backwards ...
                {
                    nPara = nCurPara;
                    while ( nPara && !GetParaPortions()[nPara].IsVisible() )
                    while ( nPara && !GetParaPortions()[nPara]->IsVisible() )
                        nPara--;
                }
                OSL_ENSURE( GetParaPortions()[nPara].IsVisible(), "No visible paragraph found: UpdateSelections" );
                OSL_ENSURE( GetParaPortions()[nPara]->IsVisible(), "No visible paragraph found: UpdateSelections" );

                ParaPortion& rParaPortion = GetParaPortions()[nPara];
                EditSelection aTmpSelection( EditPaM( rParaPortion.GetNode(), 0 ) );
                ParaPortion* pParaPortion = GetParaPortions()[nPara];
                EditSelection aTmpSelection( EditPaM( pParaPortion->GetNode(), 0 ) );
                pView->pImpEditView->SetEditSelection( aTmpSelection );
                bChanged=true;
                break;  // for loop
diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx
index 372237f..129c4d9 100644
--- a/editeng/source/editeng/impedit3.cxx
+++ b/editeng/source/editeng/impedit3.cxx
@@ -356,7 +356,7 @@ bool ImpEditEngine::IsPageOverflow( ) const
void ImpEditEngine::FormatFullDoc()
{
    for ( sal_Int32 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ )
        GetParaPortions()[nPortion].MarkSelectionInvalid( 0 );
        GetParaPortions()[nPortion]->MarkSelectionInvalid( 0 );
    FormatDoc();
}

@@ -380,20 +380,20 @@ void ImpEditEngine::FormatDoc()

    for ( sal_Int32 nPara = 0; nPara < GetParaPortions().Count(); nPara++ )
    {
        ParaPortion& rParaPortion = GetParaPortions()[nPara];
        if ( rParaPortion.MustRepaint() || ( rParaPortion.IsInvalid() && rParaPortion.IsVisible() ) )
        ParaPortion* pParaPortion = GetParaPortions()[nPara];
        if ( pParaPortion->MustRepaint() || ( pParaPortion->IsInvalid() && pParaPortion->IsVisible() ) )
        {
            // No formatting should be necessary for MustRepaint()!
            if ( !rParaPortion.IsInvalid() || CreateLines( nPara, nY ) )
            if ( !pParaPortion->IsInvalid() || CreateLines( nPara, nY ) )
            {
                if ( !bGrow && GetTextRanger() )
                {
                    // For a change in height all below must be reformatted...
                    for ( sal_Int32 n = nPara+1; n < GetParaPortions().Count(); n++ )
                    {
                        ParaPortion& rPP = GetParaPortions()[n];
                        rPP.MarkSelectionInvalid( 0 );
                        rPP.GetLines().Reset();
                        ParaPortion* pPP = GetParaPortions()[n];
                        pPP->MarkSelectionInvalid( 0 );
                        pPP->GetLines().Reset();
                    }
                }
                bGrow = true;
@@ -408,12 +408,12 @@ void ImpEditEngine::FormatDoc()
                    }

                }
                rParaPortion.SetMustRepaint( false );
                pParaPortion->SetMustRepaint( false );
            }

            aRepaintParas.insert(nPara);
        }
        nY += rParaPortion.GetHeight();
        nY += pParaPortion->GetHeight();
    }

    aInvalidRect = tools::Rectangle(); // make empty
@@ -521,11 +521,11 @@ void ImpEditEngine::CheckAutoPageSize()
        {
            // Only paragraphs which are not aligned to the left need to be
            // reformatted, the height can not be changed here anymore.
            ParaPortion& rParaPortion = GetParaPortions()[nPara];
            ParaPortion* pParaPortion = GetParaPortions()[nPara];
            SvxAdjust eJustification = GetJustification( nPara );
            if ( eJustification != SvxAdjust::Left )
            {
                rParaPortion.MarkSelectionInvalid( 0 );
                pParaPortion->MarkSelectionInvalid( 0 );
                CreateLines( nPara, 0 );  // 0: For AutoPageSize no TextRange!
            }
        }
@@ -597,28 +597,28 @@ tools::Long ImpEditEngine::GetColumnWidth(const Size& rPaperSize) const

bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
{
    ParaPortion& rParaPortion = GetParaPortions()[nPara];
    ParaPortion* pParaPortion = GetParaPortions()[nPara];

    // sal_Bool: Changes in the height of paragraph Yes / No - sal_True/sal_False
    assert( rParaPortion.GetNode() && "Portion without Node in CreateLines" );
    DBG_ASSERT( rParaPortion.IsVisible(), "Invisible paragraphs not formatted!" );
    DBG_ASSERT( rParaPortion.IsInvalid(), "CreateLines: Portion not invalid!" );
    assert( pParaPortion->GetNode() && "Portion without Node in CreateLines" );
    DBG_ASSERT( pParaPortion->IsVisible(), "Invisible paragraphs not formatted!" );
    DBG_ASSERT( pParaPortion->IsInvalid(), "CreateLines: Portion not invalid!" );

    bool bProcessingEmptyLine = ( rParaPortion.GetNode()->Len() == 0 );
    bool bEmptyNodeWithPolygon = ( rParaPortion.GetNode()->Len() == 0 ) && GetTextRanger();
    bool bProcessingEmptyLine = ( pParaPortion->GetNode()->Len() == 0 );
    bool bEmptyNodeWithPolygon = ( pParaPortion->GetNode()->Len() == 0 ) && GetTextRanger();


    // Fast special treatment for empty paragraphs...

    if ( ( rParaPortion.GetNode()->Len() == 0 ) && !GetTextRanger() )
    if ( ( pParaPortion->GetNode()->Len() == 0 ) && !GetTextRanger() )
    {
        // fast special treatment...
        if ( rParaPortion.GetTextPortions().Count() )
            rParaPortion.GetTextPortions().Reset();
        if ( rParaPortion.GetLines().Count() )
            rParaPortion.GetLines().Reset();
        CreateAndInsertEmptyLine( &rParaPortion );
        return FinishCreateLines( &rParaPortion );
        if ( pParaPortion->GetTextPortions().Count() )
            pParaPortion->GetTextPortions().Reset();
        if ( pParaPortion->GetLines().Count() )
            pParaPortion->GetLines().Reset();
        CreateAndInsertEmptyLine( pParaPortion );
        return FinishCreateLines( pParaPortion );
    }

    sal_Int64 nCurrentPosY = nStartPosY;
@@ -636,16 +636,16 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
    // Always format for 100%:
    bool bMapChanged = ImpCheckRefMapMode();

    if ( rParaPortion.GetLines().Count() == 0 )
    if ( pParaPortion->GetLines().Count() == 0 )
    {
        EditLine* pL = new EditLine;
        rParaPortion.GetLines().Append(pL);
        pParaPortion->GetLines().Append(pL);
    }


    // Get Paragraph attributes...

    ContentNode* const pNode = rParaPortion.GetNode();
    ContentNode* const pNode = pParaPortion->GetNode();

    bool bRightToLeftPara = IsRightToLeft( nPara );

@@ -658,30 +658,30 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
    const SvxLineSpacingItem& rLSItem = pNode->GetContentAttribs().GetItem( EE_PARA_SBL );
    const bool bScriptSpace = pNode->GetContentAttribs().GetItem( EE_PARA_ASIANCJKSPACING ).GetValue();

    const short nInvalidDiff = rParaPortion.GetInvalidDiff();
    const sal_Int32 nInvalidStart = rParaPortion.GetInvalidPosStart();
    const short nInvalidDiff = pParaPortion->GetInvalidDiff();
    const sal_Int32 nInvalidStart = pParaPortion->GetInvalidPosStart();
    const sal_Int32 nInvalidEnd =  nInvalidStart + std::abs( nInvalidDiff );

    bool bQuickFormat = false;
    if ( !bEmptyNodeWithPolygon && !HasScriptType( nPara, i18n::ScriptType::COMPLEX ) )
    {
        if ( ( rParaPortion.IsSimpleInvalid() ) && ( nInvalidDiff > 0 ) &&
        if ( ( pParaPortion->IsSimpleInvalid() ) && ( nInvalidDiff > 0 ) &&
             ( pNode->GetString().indexOf( CH_FEATURE, nInvalidStart ) > nInvalidEnd ) )
        {
            bQuickFormat = true;
        }
        else if ( ( rParaPortion.IsSimpleInvalid() ) && ( nInvalidDiff < 0 ) )
        else if ( ( pParaPortion->IsSimpleInvalid() ) && ( nInvalidDiff < 0 ) )
        {
            // check if delete over the portion boundaries was done...
            sal_Int32 nStart = nInvalidStart;  // DOUBLE !!!!!!!!!!!!!!!
            sal_Int32 nEnd = nStart - nInvalidDiff;  // negative
            bQuickFormat = true;
            sal_Int32 nPos = 0;
            sal_Int32 nPortions = rParaPortion.GetTextPortions().Count();
            sal_Int32 nPortions = pParaPortion->GetTextPortions().Count();
            for ( sal_Int32 nTP = 0; nTP < nPortions; nTP++ )
            {
                // There must be no start / end in the deleted area.
                const TextPortion& rTP = rParaPortion.GetTextPortions()[ nTP ];
                const TextPortion& rTP = pParaPortion->GetTextPortions()[ nTP ];
                nPos = nPos + rTP.GetLen();
                if ( ( nPos > nStart ) && ( nPos < nEnd ) )
                {
@@ -702,17 +702,17 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
    if ( bEmptyNodeWithPolygon )
    {
        TextPortion* pDummyPortion = new TextPortion( 0 );
        rParaPortion.GetTextPortions().Reset();
        rParaPortion.GetTextPortions().Append(pDummyPortion);
        pParaPortion->GetTextPortions().Reset();
        pParaPortion->GetTextPortions().Append(pDummyPortion);
    }
    else if ( bQuickFormat )
    {
        // faster Method:
        RecalcTextPortion( &rParaPortion, nInvalidStart, nInvalidDiff );
        RecalcTextPortion( pParaPortion, nInvalidStart, nInvalidDiff );
    }
    else    // nRealInvalidStart can be before InvalidStart, since Portions were deleted...
    {
        CreateTextPortions( &rParaPortion, nRealInvalidStart );
        CreateTextPortions( pParaPortion, nRealInvalidStart );
    }


@@ -720,10 +720,10 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
    // Flag the line => do not remove it !


    sal_Int32 nLine = rParaPortion.GetLines().Count()-1;
    sal_Int32 nLine = pParaPortion->GetLines().Count()-1;
    for ( sal_Int32 nL = 0; nL <= nLine; nL++ )
    {
        EditLine& rLine = rParaPortion.GetLines()[nL];
        EditLine& rLine = pParaPortion->GetLines()[nL];
        if ( rLine.GetEnd() > nRealInvalidStart )  // not nInvalidStart!
        {
            nLine = nL;
@@ -733,20 +733,20 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
    }
    // Begin one line before...
    // If it is typed at the end, the line in front cannot change.
    if ( nLine && ( !rParaPortion.IsSimpleInvalid() || ( nInvalidEnd < pNode->Len() ) || ( nInvalidDiff <= 0 ) ) )
    if ( nLine && ( !pParaPortion->IsSimpleInvalid() || ( nInvalidEnd < pNode->Len() ) || ( nInvalidDiff <= 0 ) ) )
        nLine--;

    EditLine* pLine = &rParaPortion.GetLines()[nLine];
    EditLine* pLine = &pParaPortion->GetLines()[nLine];

    static const tools::Rectangle aZeroArea { Point(), Point() };
    tools::Rectangle aBulletArea( aZeroArea );
    if ( !nLine )
    {
        aBulletArea = GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos( &rParaPortion ) );
        aBulletArea = GetEditEnginePtr()->GetBulletArea( GetParaPortions().GetPos( pParaPortion ) );
        if ( !aBulletArea.IsWidthEmpty() && aBulletArea.Right() > 0 )
            rParaPortion.SetBulletX( static_cast<sal_Int32>(GetXValue( aBulletArea.Right() )) );
            pParaPortion->SetBulletX( static_cast<sal_Int32>(GetXValue( aBulletArea.Right() )) );
        else
            rParaPortion.SetBulletX( 0 ); // if Bullet is set incorrectly
            pParaPortion->SetBulletX( 0 ); // if Bullet is set incorrectly
    }


@@ -784,9 +784,9 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
            tools::Long nFI = GetXValue( rLRItem.GetTextFirstLineOffset() );
            nStartX += nFI;

            if ( !nLine && ( rParaPortion.GetBulletX() > nStartX ) )
            if ( !nLine && ( pParaPortion->GetBulletX() > nStartX ) )
            {
                    nStartX = rParaPortion.GetBulletX();
                    nStartX = pParaPortion->GetBulletX();
            }
        }

@@ -826,7 +826,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
        {
            GetTextRanger()->SetVertical( IsEffectivelyVertical() );

            tools::Long nTextY = nStartPosY + GetEditCursor( &rParaPortion, pLine, pLine->GetStart(), GetCursorFlags::NONE ).Top();
            tools::Long nTextY = nStartPosY + GetEditCursor( pParaPortion, pLine, pLine->GetStart(), GetCursorFlags::NONE ).Top();
            if ( !bSameLineAgain )
            {
                SeekCursor( pNode, nTmpPos+1, aTmpFont );
@@ -904,7 +904,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
        const EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature( pLine->GetStart() );
        while ( ( nTmpWidth < nXWidth ) && !bEOL )
        {
            const sal_Int32 nTextPortions = rParaPortion.GetTextPortions().Count();
            const sal_Int32 nTextPortions = pParaPortion->GetTextPortions().Count();
            assert(nTextPortions > 0);
            bContinueLastPortion = (nTmpPortion >= nTextPortions);
            if (bContinueLastPortion)
@@ -922,17 +922,17 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
            }

            nPortionStart = nTmpPos;
            pPortion = &rParaPortion.GetTextPortions()[nTmpPortion];
            pPortion = &pParaPortion->GetTextPortions()[nTmpPortion];
            if ( !bContinueLastPortion && pPortion->GetKind() == PortionKind::HYPHENATOR )
            {
                // Throw away a Portion, if necessary correct the one before,
                // if the Hyph portion has swallowed a character...
                sal_Int32 nTmpLen = pPortion->GetLen();
                rParaPortion.GetTextPortions().Remove( nTmpPortion );
                pParaPortion->GetTextPortions().Remove( nTmpPortion );
                if (nTmpPortion && nTmpLen)
                {
                    nTmpPortion--;
                    TextPortion& rPrev = rParaPortion.GetTextPortions()[nTmpPortion];
                    TextPortion& rPrev = pParaPortion->GetTextPortions()[nTmpPortion];
                    DBG_ASSERT( rPrev.GetKind() == PortionKind::TEXT, "Portion?!" );
                    nTmpWidth -= rPrev.GetSize().Width();
                    nTmpPos = nTmpPos - rPrev.GetLen();
@@ -940,8 +940,8 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
                    rPrev.GetSize().setWidth( -1 );
                }

                assert( nTmpPortion < rParaPortion.GetTextPortions().Count() && "No more Portions left!" );
                pPortion = &rParaPortion.GetTextPortions()[nTmpPortion];
                assert( nTmpPortion < pParaPortion->GetTextPortions().Count() && "No more Portions left!" );
                pPortion = &pParaPortion->GetTextPortions()[nTmpPortion];
            }

            if (bContinueLastPortion)
@@ -1156,7 +1156,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
                if (bContinueLastPortion)
                {
                     Size aSize( aTmpFont.QuickGetTextSize( GetRefDevice(),
                            rParaPortion.GetNode()->GetString(), nTmpPos, nPortionLen, &aBuf ));
                            pParaPortion->GetNode()->GetString(), nTmpPos, nPortionLen, &aBuf ));
                     pPortion->GetSize().AdjustWidth(aSize.Width() );
                     if (pPortion->GetSize().Height() < aSize.Height())
                         pPortion->GetSize().setHeight( aSize.Height() );
@@ -1164,7 +1164,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
                else
                {
                    pPortion->GetSize() = aTmpFont.QuickGetTextSize( GetRefDevice(),
                            rParaPortion.GetNode()->GetString(), nTmpPos, nPortionLen, &aBuf );
                            pParaPortion->GetNode()->GetString(), nTmpPos, nPortionLen, &aBuf );
                }

                // #i9050# Do Kerning also behind portions...
@@ -1213,7 +1213,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
                tools::Long nWidthAfterTab = 0;
                for ( sal_Int32 n = aCurrentTab.nTabPortion+1; n <= nTmpPortion; n++  )
                {
                    const TextPortion& rTP = rParaPortion.GetTextPortions()[n];
                    const TextPortion& rTP = pParaPortion->GetTextPortions()[n];
                    nWidthAfterTab += rTP.GetSize().Width();
                }
                tools::Long nW = nWidthAfterTab;   // Length before tab position
@@ -1226,13 +1226,13 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
                }
                else if ( aCurrentTab.aTabStop.GetAdjustment() == SvxTabAdjust::Decimal )
                {
                    OUString aText = GetSelected( EditSelection(  EditPaM( rParaPortion.GetNode(), nTmpPos ),
                                                                EditPaM( rParaPortion.GetNode(), nTmpPos + nPortionLen ) ) );
                    OUString aText = GetSelected( EditSelection(  EditPaM( pParaPortion->GetNode(), nTmpPos ),
                                                                EditPaM( pParaPortion->GetNode(), nTmpPos + nPortionLen ) ) );
                    sal_Int32 nDecPos = aText.indexOf( aCurrentTab.aTabStop.GetDecimal() );
                    if ( nDecPos != -1 )
                    {
                        nW -= rParaPortion.GetTextPortions()[nTmpPortion].GetSize().Width();
                        nW += aTmpFont.QuickGetTextSize( GetRefDevice(), rParaPortion.GetNode()->GetString(),
                        nW -= pParaPortion->GetTextPortions()[nTmpPortion].GetSize().Width();
                        nW += aTmpFont.QuickGetTextSize( GetRefDevice(), pParaPortion->GetNode()->GetString(),
                                nTmpPos, nDecPos, nullptr ).Width();
                        aCurrentTab.bValid = false;
                    }
@@ -1247,7 +1247,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
                    nW = nMaxW;
                    aCurrentTab.bValid = false;
                }
                TextPortion& rTabPortion = rParaPortion.GetTextPortions()[aCurrentTab.nTabPortion];
                TextPortion& rTabPortion = pParaPortion->GetTextPortions()[aCurrentTab.nTabPortion];
                rTabPortion.GetSize().setWidth( aCurrentTab.nTabPos - aCurrentTab.nStartPosX - nW - nStartX );
                nTmpWidth = aCurrentTab.nStartPosX + rTabPortion.GetSize().Width() + nWidthAfterTab;
            }
@@ -1286,8 +1286,8 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
            {
                DBG_ASSERT( pPortion->GetKind() == PortionKind::TEXT, "Len>1, but no TextPortion?" );
                nTmpWidth -= pPortion->GetSize().Width();
                sal_Int32 nP = SplitTextPortion( &rParaPortion, nTmpPos, pLine );
                nTmpWidth += rParaPortion.GetTextPortions()[nP].GetSize().Width();
                sal_Int32 nP = SplitTextPortion( pParaPortion, nTmpPos, pLine );
                nTmpWidth += pParaPortion->GetTextPortions()[nP].GetSize().Width();
            }
        }
        else if ( nTmpWidth >= nXWidth )
@@ -1327,8 +1327,8 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
            bEOL = true;
            bEOC = true;
            pLine->SetEnd( nPortionEnd );
            assert( rParaPortion.GetTextPortions().Count() && "No TextPortions?" );
            pLine->SetEndPortion( rParaPortion.GetTextPortions().Count() - 1 );
            assert( pParaPortion->GetTextPortions().Count() && "No TextPortions?" );
            pLine->SetEndPortion( pParaPortion->GetTextPortions().Count() - 1 );
        }

        if ( aStatus.OneCharPerLine() )
@@ -1360,7 +1360,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
                    pNode, pPortion, nPortionStart, pDXArray, 10000, true);
            }
            if( pPortion )
                ImpBreakLine( &rParaPortion, pLine, pPortion, nPortionStart,
                ImpBreakLine( pParaPortion, pLine, pPortion, nPortionStart,
                                                nRemainingWidth, bCanHyphenate && bHyphenatePara );
        }

@@ -1369,7 +1369,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )


        // CalcTextSize should be replaced by a continuous registering!
        Size aTextSize = pLine->CalcTextSize( rParaPortion );
        Size aTextSize = pLine->CalcTextSize( *pParaPortion );

        if ( aTextSize.Height() == 0 )
        {
@@ -1391,7 +1391,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
        sal_Int32 nTPos = pLine->GetStart();
        for ( sal_Int32 nP = pLine->GetStartPortion(); nP <= pLine->GetEndPortion(); nP++ )
        {
            const TextPortion& rTP = rParaPortion.GetTextPortions()[nP];
            const TextPortion& rTP = pParaPortion->GetTextPortions()[nP];
            // problem with hard font height attribute, when everything but the line break has this attribute
            if ( rTP.GetKind() != PortionKind::LINEBREAK )
            {
@@ -1483,8 +1483,8 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
            tools::Long nRemainingWidth = nMaxLineWidth - aTextSize.Width();
            if ( nRemainingWidth > 0 )
            {
                ImplExpandCompressedPortions( pLine, &rParaPortion, nRemainingWidth );
                aTextSize = pLine->CalcTextSize( rParaPortion );
                ImplExpandCompressedPortions( pLine, pParaPortion, nRemainingWidth );
                aTextSize = pLine->CalcTextSize( *pParaPortion );
            }
        }

@@ -1493,7 +1493,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
            // Width from HangingPunctuation was set to 0 in ImpBreakLine,
            // check for rel width now, maybe create compression...
            tools::Long n = nMaxLineWidth - aTextSize.Width();
            TextPortion& rTP = rParaPortion.GetTextPortions()[pLine->GetEndPortion()];
            TextPortion& rTP = pParaPortion->GetTextPortions()[pLine->GetEndPortion()];
            sal_Int32 nPosInArray = pLine->GetEnd()-1-pLine->GetStart();
            tools::Long nNewValue = ( nPosInArray ? pLine->GetCharPosArray()[ nPosInArray-1 ] : 0 ) + n;
            if (o3tl::make_unsigned(nPosInArray) < pLine->GetCharPosArray().size())
@@ -1528,7 +1528,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
                tools::Long nRemainingSpace = nMaxLineWidth - aTextSize.Width();
                pLine->SetStartPosX( nStartX );
                if ( nRemainingSpace > 0 && (!bEOC || bDistLastLine) )
                    ImpAdjustBlocks( &rParaPortion, pLine, nRemainingSpace );
                    ImpAdjustBlocks( pParaPortion, pLine, nRemainingSpace );
            }
            break;
            default:
@@ -1562,7 +1562,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
        }

        // for <0 think over !
        if ( rParaPortion.IsSimpleInvalid() )
        if ( pParaPortion->IsSimpleInvalid() )
        {
            // Change through simple Text changes...
            // Do not cancel formatting since Portions possibly have to be split
@@ -1589,7 +1589,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
                        if (bQuickFormat)
                        {
                            bLineBreak = false;
                            rParaPortion.CorrectValuesBehindLastFormattedLine( nLine );
                            pParaPortion->CorrectValuesBehindLastFormattedLine( nLine );
                            break;
                        }
                    }
@@ -1602,7 +1602,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
                    if ( nEnd == ( aSaveLine.GetEnd() + nInvalidDiff ) )
                    {
                        bLineBreak = false;
                        rParaPortion.CorrectValuesBehindLastFormattedLine( nLine );
                        pParaPortion->CorrectValuesBehindLastFormattedLine( nLine );
                        break;
                    }
                }
@@ -1619,8 +1619,8 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )

            // Next line or maybe a new line...
            pLine = nullptr;
            if ( nLine < rParaPortion.GetLines().Count()-1 )
                pLine = &rParaPortion.GetLines()[++nLine];
            if ( nLine < pParaPortion->GetLines().Count()-1 )
                pLine = &pParaPortion->GetLines()[++nLine];
            if ( pLine && ( nIndex >= pNode->Len() ) )
            {
                nDelFromLine = nLine;
@@ -1641,16 +1641,16 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
                if ( nIndex < pNode->Len() )
                {
                    pLine = new EditLine;
                    rParaPortion.GetLines().Insert(++nLine, pLine);
                    pParaPortion->GetLines().Insert(++nLine, pLine);
                }
                else if ( nIndex && bLineBreak && GetTextRanger() )
                {
                    // normally CreateAndInsertEmptyLine would be called, but I want to use
                    // CreateLines, so I need Polygon code only here...
                    TextPortion* pDummyPortion = new TextPortion( 0 );
                    rParaPortion.GetTextPortions().Append(pDummyPortion);
                    pParaPortion->GetTextPortions().Append(pDummyPortion);
                    pLine = new EditLine;
                    rParaPortion.GetLines().Insert(++nLine, pLine);
                    pParaPortion->GetLines().Insert(++nLine, pLine);
                    bForceOneRun = true;
                    bProcessingEmptyLine = true;
                }
@@ -1667,14 +1667,14 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
    }   // while ( Index < Len )

    if ( nDelFromLine >= 0 )
        rParaPortion.GetLines().DeleteFromLine( nDelFromLine );
        pParaPortion->GetLines().DeleteFromLine( nDelFromLine );

    DBG_ASSERT( rParaPortion.GetLines().Count(), "No line after CreateLines!" );
    DBG_ASSERT( pParaPortion->GetLines().Count(), "No line after CreateLines!" );

    if ( bLineBreak )
        CreateAndInsertEmptyLine( &rParaPortion );
        CreateAndInsertEmptyLine( pParaPortion );

    bool bHeightChanged = FinishCreateLines( &rParaPortion );
    bool bHeightChanged = FinishCreateLines( pParaPortion );

    if ( bMapChanged )
        GetRefDevice()->Pop();
@@ -2617,9 +2617,9 @@ void ImpEditEngine::SetTextRanger( std::unique_ptr<TextRanger> pRanger )

    for ( sal_Int32 nPara = 0; nPara < GetParaPortions().Count(); nPara++ )
    {
        ParaPortion& rParaPortion = GetParaPortions()[nPara];
        rParaPortion.MarkSelectionInvalid( 0 );
        rParaPortion.GetLines().Reset();
        ParaPortion* pParaPortion = GetParaPortions()[nPara];
        pParaPortion->MarkSelectionInvalid( 0 );
        pParaPortion->GetLines().Reset();
    }

    FormatFullDoc();
@@ -3128,7 +3128,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
    tools::Long nFirstVisYPos = - rOutDev.GetMapMode().GetOrigin().Y();

    DBG_ASSERT( GetParaPortions().Count(), "No ParaPortion?!" );
    SvxFont aTmpFont( GetParaPortions()[0].GetNode()->GetCharAttribs().GetDefFont() );
    SvxFont aTmpFont( GetParaPortions()[0]->GetNode()->GetCharAttribs().GetDefFont() );
    vcl::PDFExtOutDevData* const pPDFExtOutDevData = dynamic_cast< vcl::PDFExtOutDevData* >( rOutDev.GetExtOutDevData() );

    // In the case of rotated text is aStartPos considered TopLeft because
@@ -3157,17 +3157,18 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po

    for ( sal_Int32 n = 0; n < GetParaPortions().Count(); n++ )
    {
        const ParaPortion& rPortion = GetParaPortions()[n];
        const ParaPortion* const pPortion = GetParaPortions()[n];
        assert( pPortion && "NULL-Pointer in TokenList in Paint" );
        // if when typing idle formatting,  asynchronous Paint.
        // Invisible Portions may be invalid.
        if ( rPortion.IsVisible() && rPortion.IsInvalid() )
        if ( pPortion->IsVisible() && pPortion->IsInvalid() )
            return;

        if ( pPDFExtOutDevData )
            pPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph );

        const tools::Long nParaHeight = rPortion.GetHeight();
        if ( rPortion.IsVisible() && (
        const tools::Long nParaHeight = pPortion->GetHeight();
        if ( pPortion->IsVisible() && (
                ( !IsEffectivelyVertical() && ( ( aStartPos.Y() + nParaHeight ) > aClipRect.Top() ) ) ||
                ( IsEffectivelyVertical() && IsTopToBottom() && ( ( aStartPos.X() - nParaHeight ) < aClipRect.Right() ) ) ||
                ( IsEffectivelyVertical() && !IsTopToBottom() && ( ( aStartPos.X() + nParaHeight ) > aClipRect.Left() ) ) ) )
@@ -3177,21 +3178,21 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po

            // Over the lines of the paragraph...

            const sal_Int32 nLines = rPortion.GetLines().Count();
            const sal_Int32 nLines = pPortion->GetLines().Count();
            const sal_Int32 nLastLine = nLines-1;

            bool bEndOfParagraphWritten(false);

            adjustYDirectionAware(aStartPos, rPortion.GetFirstLineOffset());
            adjustYDirectionAware(aStartPos, pPortion->GetFirstLineOffset());

            const SvxLineSpacingItem& rLSItem = rPortion.GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
            const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
            sal_uInt16 nSBL = ( rLSItem.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Fix )
                                ? GetYValue( rLSItem.GetInterLineSpace() ) : 0;
            bool bPaintBullet (false);

            for ( sal_Int32 nLine = 0; nLine < nLines; nLine++ )
            {
                const EditLine* const pLine = &rPortion.GetLines()[nLine];
                const EditLine* const pLine = &pPortion->GetLines()[nLine];
                assert( pLine && "NULL-Pointer in the line iterator in UpdateViews" );
                sal_Int32 nIndex = pLine->GetStart();
                tools::Long nLineHeight = pLine->GetHeight();
@@ -3231,10 +3232,10 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po

                    for ( sal_Int32 nPortion = pLine->GetStartPortion(); nPortion <= pLine->GetEndPortion(); nPortion++ )
                    {
                        DBG_ASSERT( rPortion.GetTextPortions().Count(), "Line without Textportion in Paint!" );
                        const TextPortion& rTextPortion = rPortion.GetTextPortions()[nPortion];
                        DBG_ASSERT( pPortion->GetTextPortions().Count(), "Line without Textportion in Paint!" );
                        const TextPortion& rTextPortion = pPortion->GetTextPortions()[nPortion];

                        const tools::Long nPortionXOffset = GetPortionXOffset( &rPortion, pLine, nPortion );
                        const tools::Long nPortionXOffset = GetPortionXOffset( pPortion, pLine, nPortion );
                        setXDirectionAwareFrom(aTmpPos, aStartPos);
                        adjustXDirectionAware(aTmpPos, nPortionXOffset);
                        if (isXOverflowDirectionAware(aTmpPos, aClipRect))
@@ -3246,7 +3247,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
                            case PortionKind::FIELD:
                            case PortionKind::HYPHENATOR:
                            {
                                SeekCursor( rPortion.GetNode(), nIndex+1, aTmpFont, &rOutDev );
                                SeekCursor( pPortion->GetNode(), nIndex+1, aTmpFont, &rOutDev );

                                bool bDrawFrame = false;

@@ -3294,7 +3295,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po

                                if ( rTextPortion.GetKind() == PortionKind::TEXT )
                                {
                                    aText = rPortion.GetNode()->GetString();
                                    aText = pPortion->GetNode()->GetString();
                                    nTextStart = nIndex;
                                    nTextLen = rTextPortion.GetLen();
                                    pDXArray = o3tl::span(pLine->GetCharPosArray().data() + (nIndex - pLine->GetStart()),
@@ -3375,7 +3376,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
                                }
                                else if ( rTextPortion.GetKind() == PortionKind::FIELD )
                                {
                                    const EditCharAttrib* pAttr = rPortion.GetNode()->GetCharAttribs().FindFeature(nIndex);
                                    const EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature(nIndex);
                                    assert( pAttr && "Field not found");
                                    DBG_ASSERT( dynamic_cast< const SvxFieldItem* >( pAttr->GetItem() ) !=  nullptr, "Field of the wrong type! ");
                                    aText = static_cast<const EditCharAttribField*>(pAttr)->GetFieldValue();
@@ -3471,7 +3472,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po

                                    if(GetStatus().DoOnlineSpelling() && rTextPortion.GetLen())
                                    {
                                        WrongList* pWrongs = rPortion.GetNode()->GetWrongList();
                                        WrongList* pWrongs = pPortion->GetNode()->GetWrongList();

                                        if(pWrongs && !pWrongs->empty())
                                        {
@@ -3518,7 +3519,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po

                                    if(PortionKind::FIELD == rTextPortion.GetKind())
                                    {
                                        const EditCharAttrib* pAttr = rPortion.GetNode()->GetCharAttribs().FindFeature(nIndex);
                                        const EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature(nIndex);
                                        const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem());

                                        if(pFieldItem)
@@ -3530,7 +3531,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
                                    // support for EOC, EOW, EOS TEXT comments. To support that,
                                    // the locale is needed. With the locale and a XBreakIterator it is
                                    // possible to re-create the text marking info on primitive level
                                    const lang::Locale aLocale(GetLocale(EditPaM(rPortion.GetNode(), nIndex + 1)));
                                    const lang::Locale aLocale(GetLocale(EditPaM(pPortion->GetNode(), nIndex + 1)));

                                    // create EOL and EOP bools
                                    const bool bEndOfLine(nPortion == pLine->GetEndPortion());
@@ -3597,20 +3598,20 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
                                            // base line of the original font height...
                                            // But only if there was something underlined before!
                                            bool bSpecialUnderline = false;
                                            EditCharAttrib* pPrev = rPortion.GetNode()->GetCharAttribs().FindAttrib( EE_CHAR_ESCAPEMENT, nIndex );
                                            EditCharAttrib* pPrev = pPortion->GetNode()->GetCharAttribs().FindAttrib( EE_CHAR_ESCAPEMENT, nIndex );
                                            if ( pPrev )
                                            {
                                                SvxFont aDummy;
                                                // Underscore in front?
                                                if ( pPrev->GetStart() )
                                                {
                                                    SeekCursor( rPortion.GetNode(), pPrev->GetStart(), aDummy );
                                                    SeekCursor( pPortion->GetNode(), pPrev->GetStart(), aDummy );
                                                    if ( aDummy.GetUnderline() != LINESTYLE_NONE )
                                                        bSpecialUnderline = true;
                                                }
                                                if ( !bSpecialUnderline && ( pPrev->GetEnd() < rPortion.GetNode()->Len() ) )
                                                if ( !bSpecialUnderline && ( pPrev->GetEnd() < pPortion->GetNode()->Len() ) )
                                                {
                                                    SeekCursor( rPortion.GetNode(), pPrev->GetEnd()+1, aDummy );
                                                    SeekCursor( pPortion->GetNode(), pPrev->GetEnd()+1, aDummy );
                                                    if ( aDummy.GetUnderline() != LINESTYLE_NONE )
                                                        bSpecialUnderline = true;
                                                }
@@ -3670,7 +3671,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
                                        {
                                            if ( rTextPortion.GetKind() == PortionKind::FIELD )
                                            {
                                                const EditCharAttrib* pAttr = rPortion.GetNode()->GetCharAttribs().FindFeature(nIndex);
                                                const EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature(nIndex);
                                                const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem());
                                                if( pFieldItem )
                                                {
@@ -3692,7 +3693,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
                                        }
                                    }

                                    const WrongList* const pWrongList = rPortion.GetNode()->GetWrongList();
                                    const WrongList* const pWrongList = pPortion->GetNode()->GetWrongList();
                                    if ( GetStatus().DoOnlineSpelling() && pWrongList && !pWrongList->empty() && rTextPortion.GetLen() )
                                    {
                                        {//#105750# adjust LinePos for superscript or subscript text
@@ -3705,7 +3706,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
                                        }
                                        Color aOldColor( rOutDev.GetLineColor() );
                                        rOutDev.SetLineColor( GetColorConfig().GetColorValue( svtools::SPELL ).nColor );
                                        lcl_DrawRedLines( rOutDev, aTmpFont.GetFontSize().Height(), aRedLineTmpPos, static_cast<size_t>(nIndex), static_cast<size_t>(nIndex) + rTextPortion.GetLen(), pDXArray, rPortion.GetNode()->GetWrongList(), nOrientation, aOrigin, IsEffectivelyVertical(), rTextPortion.IsRightToLeft() );
                                        lcl_DrawRedLines( rOutDev, aTmpFont.GetFontSize().Height(), aRedLineTmpPos, static_cast<size_t>(nIndex), static_cast<size_t>(nIndex) + rTextPortion.GetLen(), pDXArray, pPortion->GetNode()->GetWrongList(), nOrientation, aOrigin, IsEffectivelyVertical(), rTextPortion.IsRightToLeft() );
                                        rOutDev.SetLineColor( aOldColor );
                                    }
                                }
@@ -3717,7 +3718,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
                                    // add a meta file comment if we record to a metafile
                                    if( bMetafileValid )
                                    {
                                        const EditCharAttrib* pAttr = rPortion.GetNode()->GetCharAttribs().FindFeature(nIndex);
                                        const EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature(nIndex);
                                        assert( pAttr && "Field not found" );

                                        const SvxFieldItem* pFieldItem = dynamic_cast<const SvxFieldItem*>(pAttr->GetItem());
@@ -3739,7 +3740,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po
                            {
                                if ( rTextPortion.GetExtraValue() && ( rTextPortion.GetExtraValue() != ' ' ) )
                                {
                                    SeekCursor( rPortion.GetNode(), nIndex+1, aTmpFont, &rOutDev );
                                    SeekCursor( pPortion->GetNode(), nIndex+1, aTmpFont, &rOutDev );
                                    aTmpFont.SetTransparent( false );
                                    aTmpFont.SetEscapement( 0 );
                                    aTmpFont.SetPhysFont(rOutDev);
@@ -3822,7 +3823,7 @@ void ImpEditEngine::Paint( OutputDevice& rOutDev, tools::Rectangle aClipRect, Po

            if ( !aStatus.IsOutliner() )
            {
                const SvxULSpaceItem& rULItem = rPortion.GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
                const SvxULSpaceItem& rULItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
                tools::Long nUL = GetYValue( rULItem.GetLower() );
                adjustYDirectionAware(aStartPos, nUL);
            }
@@ -3919,7 +3920,7 @@ void ImpEditEngine::InsertContent( ContentNode* pNode, sal_Int32 nPos )
{
    DBG_ASSERT( pNode, "NULL-Pointer in InsertContent! " );
    DBG_ASSERT( IsInUndo(), "InsertContent only for Undo()!" );
    GetParaPortions().Insert(nPos, ParaPortion( pNode ));
    GetParaPortions().Insert(nPos, std::make_unique<ParaPortion>( pNode ));
    aEditDoc.Insert(nPos, pNode);
    if ( IsCallParaInsertedOrDeleted() )
        GetEditEnginePtr()->ParagraphInserted( nPos );
@@ -4057,18 +4058,18 @@ void ImpEditEngine::InvalidateFromParagraph( sal_Int32 nFirstInvPara )
{
    // The following paragraphs are not invalidated, since ResetHeight()
    // => size change => all the following are re-issued anyway.
    ParaPortion* pTmpPortion;
    if ( nFirstInvPara != 0 )
    {
        ParaPortion& rTmpPortion = GetParaPortions()[nFirstInvPara-1];
        rTmpPortion.MarkInvalid( rTmpPortion.GetNode()->Len(), 0 );
        rTmpPortion.ResetHeight();
        pTmpPortion = GetParaPortions()[nFirstInvPara-1];
        pTmpPortion->MarkInvalid( pTmpPortion->GetNode()->Len(), 0 );
    }
    else
    {
        ParaPortion& rTmpPortion = GetParaPortions()[0];
        rTmpPortion.MarkSelectionInvalid( 0 );
        rTmpPortion.ResetHeight();
        pTmpPortion = GetParaPortions()[0];
        pTmpPortion->MarkSelectionInvalid( 0 );
    }
    pTmpPortion->ResetHeight();
}

IMPL_LINK_NOARG(ImpEditEngine, StatusTimerHdl, Timer *, void)
@@ -4091,17 +4092,19 @@ void ImpEditEngine::CallStatusHdl()

ContentNode* ImpEditEngine::GetPrevVisNode( ContentNode const * pCurNode )
{
    const ParaPortion& rPortion1 = FindParaPortion( pCurNode );
    const ParaPortion* pPortion2 = GetPrevVisPortion( &rPortion1 );
    if ( pPortion2 )
        return pPortion2->GetNode();
    const ParaPortion* pPortion = FindParaPortion( pCurNode );
    DBG_ASSERT( pPortion, "GetPrevVisibleNode: No matching portion!" );
    pPortion = GetPrevVisPortion( pPortion );
    if ( pPortion )
        return pPortion->GetNode();
    return nullptr;
}

ContentNode* ImpEditEngine::GetNextVisNode( ContentNode const * pCurNode )
{
    const ParaPortion& rPortion = FindParaPortion( pCurNode );
    const ParaPortion* pPortion = GetNextVisPortion( &rPortion );
    const ParaPortion* pPortion = FindParaPortion( pCurNode );
    DBG_ASSERT( pPortion, "GetNextVisibleNode: No matching portion!" );
    pPortion = GetNextVisPortion( pPortion );
    if ( pPortion )
        return pPortion->GetNode();
    return nullptr;
@@ -4110,9 +4113,10 @@ ContentNode* ImpEditEngine::GetNextVisNode( ContentNode const * pCurNode )
const ParaPortion* ImpEditEngine::GetPrevVisPortion( const ParaPortion* pCurPortion ) const
{
    sal_Int32 nPara = GetParaPortions().GetPos( pCurPortion );
    const ParaPortion* pPortion = nPara ? &GetParaPortions()[--nPara] : nullptr;
    DBG_ASSERT( nPara < GetParaPortions().Count() , "Portion not found: GetPrevVisPortion" );
    const ParaPortion* pPortion = nPara ? GetParaPortions()[--nPara] : nullptr;
    while ( pPortion && !pPortion->IsVisible() )
        pPortion = nPara ? &GetParaPortions()[--nPara] : nullptr;
        pPortion = nPara ? GetParaPortions()[--nPara] : nullptr;

    return pPortion;
}
@@ -4141,7 +4145,7 @@ tools::Long ImpEditEngine::CalcVertLineSpacing(Point& rStartPos) const
            // All paragraphs must have the block justification set.
            return 0;

        const ParaPortion* pPortion = &rParaPortions[i];
        const ParaPortion* pPortion = rParaPortions[i];
        nTotalOccupiedHeight += pPortion->GetFirstLineOffset();

        const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem(EE_PARA_SBL);
@@ -4219,7 +4223,7 @@ void ImpEditEngine::FormatAndLayout( EditView* pCurView, bool bCalledFromUndo )
        if (bCalledFromUndo)
            // in order to make bullet points that have had their styles changed, redraw themselves
            for ( sal_Int32 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ )
                GetParaPortions()[nPortion].MarkInvalid( 0, 0 );
                GetParaPortions()[nPortion]->MarkInvalid( 0, 0 );
        FormatDoc();
        UpdateViews( pCurView );
    }
@@ -4636,8 +4640,8 @@ void ImpEditEngine::ImplUpdateOverflowingParaNum(tools::Long nPaperHeight)
    tools::Long nPH;

    for ( sal_Int32 nPara = 0; nPara < GetParaPortions().Count(); nPara++ ) {
        ParaPortion& rPara = GetParaPortions()[nPara];
        nPH = rPara.GetHeight();
        ParaPortion* pPara = GetParaPortions()[nPara];
        nPH = pPara->GetHeight();
        nY += nPH;
        if ( nY > nPaperHeight /*nCurTextHeight*/ ) // found first paragraph overflowing
        {
@@ -4656,13 +4660,13 @@ void ImpEditEngine::ImplUpdateOverflowingLineNum(tools::Long nPaperHeight,
    tools::Long nY = nHeightBeforeOverflowingPara;
    tools::Long nLH;

    ParaPortion& rPara = GetParaPortions()[nOverflowingPara];
    ParaPortion *pPara = GetParaPortions()[nOverflowingPara];

    // Like UpdateOverflowingParaNum but for each line in the first
    //  overflowing paragraph.
    for ( sal_Int32 nLine = 0; nLine < rPara.GetLines().Count(); nLine++ ) {
    for ( sal_Int32 nLine = 0; nLine < pPara->GetLines().Count(); nLine++ ) {
        // XXX: We must use a reference here because the copy constructor resets the height
        EditLine &aLine = rPara.GetLines()[nLine];
        EditLine &aLine = pPara->GetLines()[nLine];
        nLH = aLine.GetHeight();
        nY += nLH;

diff --git a/editeng/source/editeng/impedit4.cxx b/editeng/source/editeng/impedit4.cxx
index 8d7fca6..f8b2c37 100644
--- a/editeng/source/editeng/impedit4.cxx
+++ b/editeng/source/editeng/impedit4.cxx
@@ -540,20 +540,21 @@ ErrCode ImpEditEngine::WriteRTF( SvStream& rOutput, EditSelection aSel )
            rOutput.WriteChar( ' ' ); // Separator

        ItemList aAttribItems;
        ParaPortion& rParaPortion = FindParaPortion( pNode );
        ParaPortion* pParaPortion = FindParaPortion( pNode );
        DBG_ASSERT( pParaPortion, "Portion not found: WriteRTF" );

        sal_Int32 nIndex = 0;
        sal_Int32 nStartPos = 0;
        sal_Int32 nEndPos = pNode->Len();
        sal_Int32 nStartPortion = 0;
        sal_Int32 nEndPortion = rParaPortion.GetTextPortions().Count() - 1;
        sal_Int32 nEndPortion = pParaPortion->GetTextPortions().Count() - 1;
        bool bFinishPortion = false;
        sal_Int32 nPortionStart;

        if ( nNode == nStartNode )
        {
            nStartPos = aSel.Min().GetIndex();
            nStartPortion = rParaPortion.GetTextPortions().FindPortion( nStartPos, nPortionStart );
            nStartPortion = pParaPortion->GetTextPortions().FindPortion( nStartPos, nPortionStart );
            if ( nStartPos != 0 )
            {
                aAttribItems.Clear();
@@ -571,14 +572,14 @@ ErrCode ImpEditEngine::WriteRTF( SvStream& rOutput, EditSelection aSel )
        if ( nNode == nEndNode ) // can also be == nStart!
        {
            nEndPos = aSel.Max().GetIndex();
            nEndPortion = rParaPortion.GetTextPortions().FindPortion( nEndPos, nPortionStart );
            nEndPortion = pParaPortion->GetTextPortions().FindPortion( nEndPos, nPortionStart );
        }

        const EditCharAttrib* pNextFeature = pNode->GetCharAttribs().FindFeature(nIndex);
        // start at 0, so the index is right ...
        for ( sal_Int32 n = 0; n <= nEndPortion; n++ )
        {
            const TextPortion& rTextPortion = rParaPortion.GetTextPortions()[n];
            const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[n];
            if ( n < nStartPortion )
            {
                nIndex = nIndex + rTextPortion.GetLen();
@@ -1007,8 +1008,8 @@ std::unique_ptr<EditTextObject> ImpEditEngine::CreateTextObject( EditSelection a

        if ( bOnlyFullParagraphs )
        {
            const ParaPortion& rParaPortion = GetParaPortions()[nNode];
            nTextPortions += rParaPortion.GetTextPortions().Count();
            const ParaPortion* pParaPortion = GetParaPortions()[nNode];
            nTextPortions += pParaPortion->GetTextPortions().Count();
        }

        sal_Int32 nStartPos = 0;
@@ -1084,39 +1085,39 @@ std::unique_ptr<EditTextObject> ImpEditEngine::CreateTextObject( EditSelection a
        pTxtObj->SetPortionInfo(std::unique_ptr<XParaPortionList>(pXList));
        for ( nNode = nStartNode; nNode <= nEndNode; nNode++  )
        {
            const ParaPortion& rParaPortion = GetParaPortions()[nNode];
            const ParaPortion* pParaPortion = GetParaPortions()[nNode];
            XParaPortion* pX = new XParaPortion;
            pXList->push_back(pX);

            pX->nHeight = rParaPortion.GetHeight();
            pX->nFirstLineOffset = rParaPortion.GetFirstLineOffset();
            pX->nHeight = pParaPortion->GetHeight();
            pX->nFirstLineOffset = pParaPortion->GetFirstLineOffset();

            // The TextPortions
            sal_uInt16 nCount = rParaPortion.GetTextPortions().Count();
            sal_uInt16 nCount = pParaPortion->GetTextPortions().Count();
            sal_uInt16 n;
            for ( n = 0; n < nCount; n++ )
            {
                const TextPortion& rTextPortion = rParaPortion.GetTextPortions()[n];
                const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[n];
                TextPortion* pNew = new TextPortion( rTextPortion );
                pX->aTextPortions.Append(pNew);
            }

            // The lines
            nCount = rParaPortion.GetLines().Count();
            nCount = pParaPortion->GetLines().Count();
            for ( n = 0; n < nCount; n++ )
            {
                const EditLine& rLine = rParaPortion.GetLines()[n];
                const EditLine& rLine = pParaPortion->GetLines()[n];
                EditLine* pNew = rLine.Clone();
                pX->aLines.Append(pNew);
            }
#ifdef DBG_UTIL
            sal_uInt16 nTest;
            int nTPLen = 0, nTxtLen = 0;
            for ( nTest = rParaPortion.GetTextPortions().Count(); nTest; )
                nTPLen += rParaPortion.GetTextPortions()[--nTest].GetLen();
            for ( nTest = rParaPortion.GetLines().Count(); nTest; )
                nTxtLen += rParaPortion.GetLines()[--nTest].GetLen();
            DBG_ASSERT( ( nTPLen == rParaPortion.GetNode()->Len() ) && ( nTxtLen == rParaPortion.GetNode()->Len() ), "CreateBinTextObject: ParaPortion not completely formatted!" );
            for ( nTest = pParaPortion->GetTextPortions().Count(); nTest; )
                nTPLen += pParaPortion->GetTextPortions()[--nTest].GetLen();
            for ( nTest = pParaPortion->GetLines().Count(); nTest; )
                nTxtLen += pParaPortion->GetLines()[--nTest].GetLen();
            DBG_ASSERT( ( nTPLen == pParaPortion->GetNode()->Len() ) && ( nTxtLen == pParaPortion->GetNode()->Len() ), "CreateBinTextObject: ParaPortion not completely formatted!" );
#endif
        }
    }
@@ -1199,8 +1200,9 @@ EditSelection ImpEditEngine::InsertTextObject( const EditTextObject& rTextObject

        aPaM = ImpFastInsertText( aPaM, pC->GetText() );

        ParaPortion& rPortion = FindParaPortion( aPaM.GetNode() );
        rPortion.MarkInvalid( nStartPos, pC->GetText().getLength() );
        ParaPortion* pPortion = FindParaPortion( aPaM.GetNode() );
        DBG_ASSERT( pPortion, "Blind Portion in FastInsertText" );
        pPortion->MarkInvalid( nStartPos, pC->GetText().getLength() );

        // Character attributes ...
        bool bAllreadyHasAttribs = aPaM.GetNode()->GetCharAttribs().Count() != 0;
@@ -1248,7 +1250,7 @@ EditSelection ImpEditEngine::InsertTextObject( const EditTextObject& rTextObject
                UpdateFields();

            // Otherwise, quick format => no attributes!
            rPortion.MarkSelectionInvalid( nStartPos );
            pPortion->MarkSelectionInvalid( nStartPos );
        }

#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
@@ -1278,40 +1280,41 @@ EditSelection ImpEditEngine::InsertTextObject( const EditTextObject& rTextObject
            if ( bNewContent && bUsePortionInfo )
            {
                const XParaPortion& rXP = (*pPortionInfo)[n];
                ParaPortion& rParaPortion = GetParaPortions()[ nPara ];
                rParaPortion.nHeight = rXP.nHeight;
                rParaPortion.nFirstLineOffset = rXP.nFirstLineOffset;
                rParaPortion.bForceRepaint = true;
                rParaPortion.SetValid();   // Do not format
                ParaPortion* pParaPortion = GetParaPortions()[ nPara ];
                DBG_ASSERT( pParaPortion, "InsertBinTextObject: ParaPortion?" );
                pParaPortion->nHeight = rXP.nHeight;
                pParaPortion->nFirstLineOffset = rXP.nFirstLineOffset;
                pParaPortion->bForceRepaint = true;
                pParaPortion->SetValid();   // Do not format

                // The Text Portions
                rParaPortion.GetTextPortions().Reset();
                pParaPortion->GetTextPortions().Reset();
                sal_uInt16 nCount = rXP.aTextPortions.Count();
                for ( sal_uInt16 _n = 0; _n < nCount; _n++ )
                {
                    const TextPortion& rTextPortion = rXP.aTextPortions[_n];
                    TextPortion* pNew = new TextPortion( rTextPortion );
                    rParaPortion.GetTextPortions().Append(pNew);
                    pParaPortion->GetTextPortions().Append(pNew);
                }

                // The lines
                rParaPortion.GetLines().Reset();
                pParaPortion->GetLines().Reset();
                nCount = rXP.aLines.Count();
                for ( sal_uInt16 m = 0; m < nCount; m++ )
                {
                    const EditLine& rLine = rXP.aLines[m];
                    EditLine* pNew = rLine.Clone();
                    pNew->SetInvalid(); // Paint again!
                    rParaPortion.GetLines().Append(pNew);
                    pParaPortion->GetLines().Append(pNew);
                }
#ifdef DBG_UTIL
                sal_uInt16 nTest;
                int nTPLen = 0, nTxtLen = 0;
                for ( nTest = rParaPortion.GetTextPortions().Count(); nTest; )
                    nTPLen += rParaPortion.GetTextPortions()[--nTest].GetLen();
                for ( nTest = rParaPortion.GetLines().Count(); nTest; )
                    nTxtLen += rParaPortion.GetLines()[--nTest].GetLen();
                DBG_ASSERT( ( nTPLen == rParaPortion.GetNode()->Len() ) && ( nTxtLen == rParaPortion.GetNode()->Len() ), "InsertTextObject: ParaPortion not completely formatted!" );
                for ( nTest = pParaPortion->GetTextPortions().Count(); nTest; )
                    nTPLen += pParaPortion->GetTextPortions()[--nTest].GetLen();
                for ( nTest = pParaPortion->GetLines().Count(); nTest; )
                    nTxtLen += pParaPortion->GetLines()[--nTest].GetLen();
                DBG_ASSERT( ( nTPLen == pParaPortion->GetNode()->Len() ) && ( nTxtLen == pParaPortion->GetNode()->Len() ), "InsertTextObject: ParaPortion not completely formatted!" );
#endif
            }
        }
@@ -2950,8 +2953,8 @@ EditSelection ImpEditEngine::TransliterateText( const EditSelection& rSelection,
                    aNewSel.Max().SetIndex( aNewSel.Max().GetIndex() + nDiffs );

                sal_Int32 nSelNode = aEditDoc.GetPos( rData.aSelection.Min().GetNode() );
                ParaPortion& rParaPortion = GetParaPortions()[nSelNode];
                rParaPortion.MarkSelectionInvalid( rData.nStart );
                ParaPortion* pParaPortion = GetParaPortions()[nSelNode];
                pParaPortion->MarkSelectionInvalid( rData.nStart );
            }
        }
    }
diff --git a/editeng/source/editeng/impedit5.cxx b/editeng/source/editeng/impedit5.cxx
index c9d7563..1fbb56a 100644
--- a/editeng/source/editeng/impedit5.cxx
+++ b/editeng/source/editeng/impedit5.cxx
@@ -523,7 +523,7 @@ void ImpEditEngine::SetAttribs( EditSelection aSel, const SfxItemSet& rSet, SetA
        DBG_ASSERT( GetParaPortions().SafeGetObject( nNode ), "Portion not found: SetAttribs" );

        ContentNode* pNode = aEditDoc.GetObject( nNode );
        ParaPortion& rPortion = GetParaPortions()[nNode];
        ParaPortion* pPortion = GetParaPortions()[nNode];

        const sal_Int32 nStartPos = nNode==nStartNode ? aSel.Min().GetIndex() : 0;
        const sal_Int32 nEndPos = nNode==nEndNode ? aSel.Max().GetIndex() : pNode->Len(); // can also be == nStart!
@@ -565,14 +565,14 @@ void ImpEditEngine::SetAttribs( EditSelection aSel, const SfxItemSet& rSet, SetA

        if ( bParaAttribFound )
        {
            ParaAttribsChanged( rPortion.GetNode() );
            ParaAttribsChanged( pPortion->GetNode() );
        }
        else if ( bCharAttribFound )
        {
            bFormatted = false;
            if ( !pNode->Len() || ( nStartPos != nEndPos  ) )
            {
                rPortion.MarkSelectionInvalid( nStartPos );
                pPortion->MarkSelectionInvalid( nStartPos );
                if ( bCheckLanguage )
                    pNode->GetWrongList()->SetInvalidRange(nStartPos, nEndPos);
            }
@@ -603,7 +603,7 @@ void ImpEditEngine::RemoveCharAttribs( EditSelection aSel, EERemoveParaAttribsMo
    for ( sal_Int32 nNode = nStartNode; nNode <= nEndNode; nNode++ )
    {
        ContentNode* pNode = aEditDoc.GetObject( nNode );
        ParaPortion& rPortion = GetParaPortions()[nNode];
        ParaPortion* pPortion = GetParaPortions()[nNode];

        DBG_ASSERT( aEditDoc.GetObject( nNode ), "Node not found: SetAttribs" );
        DBG_ASSERT( GetParaPortions().SafeGetObject( nNode ), "Portion not found: SetAttribs" );
@@ -637,7 +637,7 @@ void ImpEditEngine::RemoveCharAttribs( EditSelection aSel, EERemoveParaAttribsMo
        if ( bChanged && !bRemoveParaAttribs )
        {
            bFormatted = false;
            rPortion.MarkSelectionInvalid( nStartPos );
            pPortion->MarkSelectionInvalid( nStartPos );
        }
    }
}