speed up loading large ODS a little

by flattening the ParaPortionList, which reduces allocations

Change-Id: I7b350335e336f92bb048905c2b2f06378c8a3423
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/115061
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 9b35cfe..7017516 100644
--- a/editeng/inc/editdoc.hxx
+++ b/editeng/inc/editdoc.hxx
@@ -433,8 +433,10 @@ class TextPortionList
    PortionsType maPortions;

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

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

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

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

    EditLine*       Clone() const;

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

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

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

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

                        ParaPortion( const ParaPortion& ) = delete;

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

    sal_Int32 GetLineNumber( sal_Int32 nIndex ) const;

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

    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);
    ParaPortion Remove(sal_Int32 nPos);
    ParaPortion& Insert(sal_Int32 nPos, ParaPortion&& p);
    void Append(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 57fb3b1..70e86b7 100644
--- a/editeng/qa/unit/core-test.cxx
+++ b/editeng/qa/unit/core-test.cxx
@@ -191,8 +191,8 @@ void Test::testLineSpacing()
        aEditEngine.QuickSetAttribs(*pSet, aSelection);

        // Assert changes
        ParaPortion* pParaPortion = aEditEngine.GetParaPortions()[0];
        ContentNode* const pNode = pParaPortion->GetNode();
        ParaPortion& rParaPortion = aEditEngine.GetParaPortions()[0];
        ContentNode* const pNode = rParaPortion.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 c54d01a..9a00580 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* pPPortion = pEE->pImpEditEngine->GetParaPortions()[nPortion];
        ParaPortion& rPPortion = pEE->pImpEditEngine->GetParaPortions()[nPortion];
        fprintf( fp, "\nParagraph %" SAL_PRIdINT32 ": Length = %" SAL_PRIdINT32 ", Invalid = %i\nText = '%s'",
                 nPortion, pPPortion->GetNode()->Len(), pPPortion->IsInvalid(),
                 OUStringToOString(pPPortion->GetNode()->GetString(), RTL_TEXTENCODING_UTF8).getStr() );
                 nPortion, rPPortion.GetNode()->Len(), rPPortion.IsInvalid(),
                 OUStringToOString(rPPortion.GetNode()->GetString(), RTL_TEXTENCODING_UTF8).getStr() );
        fprintf( fp, "\nVorlage:" );
        SfxStyleSheet* pStyle = pPPortion->GetNode()->GetStyleSheet();
        SfxStyleSheet* pStyle = rPPortion.GetNode()->GetStyleSheet();
        if ( pStyle )
            fprintf( fp, " %s", OUStringToOString( pStyle->GetName(), RTL_TEXTENCODING_UTF8).getStr() );
        fprintf( fp, "\nParagraph attribute:" );
        DbgOutItemSet( fp, pPPortion->GetNode()->GetContentAttribs().GetItems(), false, false );
        DbgOutItemSet( fp, rPPortion.GetNode()->GetContentAttribs().GetItems(), false, false );

        fprintf( fp, "\nCharacter attribute:" );
        bool bZeroAttr = false;
        for ( sal_Int32 z = 0; z < pPPortion->GetNode()->GetCharAttribs().Count(); ++z )
        for ( sal_Int32 z = 0; z < rPPortion.GetNode()->GetCharAttribs().Count(); ++z )
        {
            const std::unique_ptr<EditCharAttrib>& rAttr = pPPortion->GetNode()->GetCharAttribs().GetAttribs()[z];
            const std::unique_ptr<EditCharAttrib>& rAttr = rPPortion.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 = pPPortion->GetTextPortions().Count();
        const sal_Int32 nTextPortions = rPPortion.GetTextPortions().Count();
        OStringBuffer aPortionStr("\nText portions: #");
        aPortionStr.append(nTextPortions);
        aPortionStr.append(" \nA");
        aPortionStr.append(nPortion);
        aPortionStr.append(": Paragraph Length = ");
        aPortionStr.append(pPPortion->GetNode()->Len());
        aPortionStr.append(rPPortion.GetNode()->Len());
        aPortionStr.append("\nA");
        aPortionStr.append(nPortion);
        aPortionStr.append(": ");
        sal_Int32 n = 0;
        for ( sal_Int32 z = 0; z < nTextPortions; ++z )
        {
            TextPortion& rPortion = pPPortion->GetTextPortions()[z];
            TextPortion& rPortion = rPPortion.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 ( pPPortion->GetNode()->Len() != n )
        if ( rPPortion.GetNode()->Len() != n )
            aPortionStr.append(" => Error !!!");
        fprintf(fp, "%s", aPortionStr.getStr());

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

            OString aLine(OUStringToOString(pPPortion->GetNode()->Copy(rLine.GetStart(), rLine.GetEnd() - rLine.GetStart()), RTL_TEXTENCODING_ASCII_US));
            OString aLine(OUStringToOString(rPPortion.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 < pPPortion->GetLines().Count(); nLine++ )
        for ( sal_Int32 nLine = 0; nLine < rPPortion.GetLines().Count(); nLine++ )
        {
            EditLine& rLine = pPPortion->GetLines()[nLine];
            EditLine& rLine = rPPortion.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 d429cbe..84ef4fe 100644
--- a/editeng/source/editeng/editdoc.cxx
+++ b/editeng/source/editeng/editdoc.cxx
@@ -369,7 +369,6 @@ TextPortionList::TextPortionList()

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

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

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

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)
    // 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)
    {
        SAL_WARN( "editeng", "ParaPortionList::Release - out of bounds pos " << nPos);
        return nullptr;
        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;
            }
        }
    }
    std::unique_ptr<ParaPortion> p = std::move(maPortions[nPos]);
    maPortions.erase(maPortions.begin()+nPos);
    return p;
    // 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;
}

void ParaPortionList::Remove(sal_Int32 nPos)
ParaPortion& ParaPortionList::operator [](sal_Int32 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);
    return maPortions[nPos];
}

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

void ParaPortionList::Append(std::unique_ptr<ParaPortion> p)
void ParaPortionList::Append(ParaPortion&& p)
{
    maPortions.push_back(std::move(p));
}
@@ -756,10 +768,9 @@ tools::Long ParaPortionList::GetYOffset(const ParaPortion* pPPortion) const
    tools::Long nHeight = 0;
    for (const auto & rPortion : maPortions)
    {
        const ParaPortion* pTmpPortion = rPortion.get();
        if ( pTmpPortion == pPPortion )
        if ( pPPortion == &rPortion )
            return nHeight;
        nHeight += pTmpPortion->GetHeight();
        nHeight += rPortion.GetHeight();
    }
    OSL_FAIL( "GetYOffset: Portion not found" );
    return nHeight;
@@ -770,7 +781,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;
    }
@@ -779,12 +790,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].get() : nullptr;
    return 0 <= nPos && nPos < static_cast<sal_Int32>(maPortions.size()) ? &maPortions[nPos] : nullptr;
}

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

#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
@@ -928,26 +939,6 @@ 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;
@@ -982,15 +973,6 @@ 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 3f11d39..65eb808 100644
--- a/editeng/source/editeng/editeng.cxx
+++ b/editeng/source/editeng/editeng.cxx
@@ -681,12 +681,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
@@ -1903,7 +1903,7 @@ void EditEngine::SetControlWord( EEControlBits nWord )
        for ( sal_Int32 n = 0; n < nNodes; n++ )
        {
            ContentNode* pNode = pImpEditEngine->GetEditDoc().GetObject( n );
            const ParaPortion* pPortion = pImpEditEngine->GetParaPortions()[n];
            const ParaPortion& rPortion = pImpEditEngine->GetParaPortions()[n];
            bool bWrongs = false;
            if (pNode->GetWrongList() != nullptr)
                bWrongs = !pNode->GetWrongList()->empty();
@@ -1913,10 +1913,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+pPortion->GetHeight()-1 );
                pImpEditEngine->aInvalidRect.SetBottom( nY + rPortion.GetHeight()-1 );
                pImpEditEngine->UpdateViews( pImpEditEngine->pActiveView );
            }
            nY += pPortion->GetHeight();
            nY += rPortion.GetHeight();
        }
    }
}
@@ -2023,12 +2023,11 @@ bool EditEngine::IsTextPos( const Point& rPaperPos, sal_uInt16 nBorder )
        EditPaM aPaM = pImpEditEngine->GetPaM( aDocPos, false );
        if ( aPaM.GetNode() )
        {
            const ParaPortion* pParaPortion = pImpEditEngine->FindParaPortion( aPaM.GetNode() );
            DBG_ASSERT( pParaPortion, "ParaPortion?" );
            const ParaPortion& rParaPortion = pImpEditEngine->FindParaPortion( aPaM.GetNode() );

            sal_Int32 nLine = pParaPortion->GetLineNumber( aPaM.GetIndex() );
            const EditLine& rLine = pParaPortion->GetLines()[nLine];
            Range aLineXPosStartEnd = pImpEditEngine->GetLineXPosStartEnd( pParaPortion, &rLine );
            sal_Int32 nLine = rParaPortion.GetLineNumber( aPaM.GetIndex() );
            const EditLine& rLine = rParaPortion.GetLines()[nLine];
            Range aLineXPosStartEnd = pImpEditEngine->GetLineXPosStartEnd( &rParaPortion, &rLine );
            if ( ( aDocPos.X() >= aLineXPosStartEnd.Min() - nBorder ) &&
                 ( aDocPos.X() <= aLineXPosStartEnd.Max() + nBorder ) )
            {
@@ -2275,8 +2274,8 @@ bool EditEngine::ShouldCreateBigTextObject() const
    sal_Int32 nParas = pImpEditEngine->GetEditDoc().Count();
    for ( sal_Int32 nPara = 0; nPara < nParas; nPara++  )
    {
        ParaPortion* pParaPortion = pImpEditEngine->GetParaPortions()[nPara];
        nTextPortions = nTextPortions + pParaPortion->GetTextPortions().Count();
        ParaPortion& rParaPortion = pImpEditEngine->GetParaPortions()[nPara];
        nTextPortions = nTextPortions + rParaPortion.GetTextPortions().Count();
    }
    return nTextPortions >= pImpEditEngine->GetBigTextObjectStart();
}
@@ -2433,11 +2432,11 @@ ParagraphInfos EditEngine::GetParagraphInfos( sal_Int32 nPara )
    aInfos.bValid = pImpEditEngine->IsFormatted();
    if ( pImpEditEngine->IsFormatted() )
    {
        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 )
        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 )
        {
            aInfos.nFirstLineHeight = pLine->GetHeight();
            aInfos.nFirstLineTextHeight = pLine->GetTxtHeight();
diff --git a/editeng/source/editeng/impedit.cxx b/editeng/source/editeng/impedit.cxx
index bdf55d2..ef5277b 100644
--- a/editeng/source/editeng/impedit.cxx
+++ b/editeng/source/editeng/impedit.cxx
@@ -1121,7 +1121,7 @@ tools::Rectangle ImpEditView::GetEditCursor() const
    if (nPara == EE_PARA_NOT_FOUND) // #i94322
        return tools::Rectangle();

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

    GetCursorFlags nShowCursorFlags = nExtraCursorFlags | GetCursorFlags::TextOnly;

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

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

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

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

    GetCursorFlags nShowCursorFlags = nExtraCursorFlags | GetCursorFlags::TextOnly;

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

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

    if ( bGotoCursor  ) // && (!pEditEngine->pImpEditEngine->GetStatus().AutoPageSize() ) )
    {
@@ -1417,8 +1417,8 @@ void ImpEditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor )
        CursorDirection nCursorDir = CursorDirection::NONE;
        if ( IsInsertMode() && !aEditSelection.HasRange() && ( pEditEngine->pImpEditEngine->HasDifferentRTLLevels( aPaM.GetNode() ) ) )
        {
            sal_uInt16 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, bool(nShowCursorFlags & GetCursorFlags::PreferPortionStart) );
            const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[nTextPortion];
            sal_uInt16 nTextPortion = rParaPortion.GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, bool(nShowCursorFlags & GetCursorFlags::PreferPortionStart) );
            const TextPortion& rTextPortion = rParaPortion.GetTextPortions()[nTextPortion];
            if (rTextPortion.IsRightToLeft())
                nCursorDir = CursorDirection::RTL;
            else
@@ -1842,8 +1842,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* pParaPortion = pEditEngine->GetParaPortions()[nPara];
        nY += pParaPortion->GetFirstLineOffset();
        const ParaPortion& rParaPortion = pEditEngine->GetParaPortions()[nPara];
        nY += rParaPortion.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 39e52c9..21de40e 100644
--- a/editeng/source/editeng/impedit.hxx
+++ b/editeng/source/editeng/impedit.hxx
@@ -754,8 +754,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 );

@@ -1208,14 +1208,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 2ea63b8..207de9d 100644
--- a/editeng/source/editeng/impedit2.cxx
+++ b/editeng/source/editeng/impedit2.cxx
@@ -236,7 +236,7 @@ void ImpEditEngine::InitDoc(bool bKeepParaAttribs)

    GetParaPortions().Reset();

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

    bFormatted = false;

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

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

            bool bWasCursorOverwrite = mpIMEInfos->bWasCursorOverwrite;

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

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

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

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

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

    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];
    const ParaPortion& rPPortion = FindParaPortion( rPaM.GetNode() );
    sal_Int32 nLine = rPPortion.GetLineNumber( rPaM.GetIndex() );
    const EditLine& rLine = rPPortion.GetLines()[nLine];

    tools::Long nX;
    if ( pView->pImpEditView->nTravelXPos == TRAVEL_X_DONTKNOW )
    {
        nX = GetXPos( pPPortion, &rLine, rPaM.GetIndex() );
        nX = GetXPos( &rPPortion, &rLine, rPaM.GetIndex() );
        pView->pImpEditView->nTravelXPos = nX+nOnePixelInRef;
    }
    else
@@ -1246,8 +1244,8 @@ EditPaM ImpEditEngine::CursorUp( const EditPaM& rPaM, EditView const * pView )
    EditPaM aNewPaM( rPaM );
    if ( nLine )    // same paragraph
    {
        const EditLine& rPrevLine = pPPortion->GetLines()[nLine-1];
        aNewPaM.SetIndex( GetChar( pPPortion, &rPrevLine, nX ) );
        const EditLine& rPrevLine = rPPortion.GetLines()[nLine-1];
        aNewPaM.SetIndex( GetChar( &rPPortion, &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
@@ -1257,7 +1255,7 @@ EditPaM ImpEditEngine::CursorUp( const EditPaM& rPaM, EditView const * pView )
    }
    else    // previous paragraph
    {
        const ParaPortion* pPrevPortion = GetPrevVisPortion( pPPortion );
        const ParaPortion* pPrevPortion = GetPrevVisPortion( &rPPortion );
        if ( pPrevPortion )
        {
            const EditLine& rLine2 = pPrevPortion->GetLines()[pPrevPortion->GetLines().Count()-1];
@@ -1273,32 +1271,31 @@ EditPaM ImpEditEngine::CursorDown( const EditPaM& rPaM, EditView const * pView )
{
    OSL_ENSURE( pView, "No View - No Cursor Movement!" );

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

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

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

EditPaM ImpEditEngine::CursorStartOfLine( const EditPaM& rPaM )
{
    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];
    const ParaPortion& rCurPortion = FindParaPortion( rPaM.GetNode() );
    sal_Int32 nLine = rCurPortion.GetLineNumber( rPaM.GetIndex() );
    const EditLine& rLine = rCurPortion.GetLines()[nLine];

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

EditPaM ImpEditEngine::CursorEndOfLine( const EditPaM& rPaM )
{
    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];
    const ParaPortion& rCurPortion = FindParaPortion( rPaM.GetNode() );
    sal_Int32 nLine = rCurPortion.GetLineNumber( rPaM.GetIndex() );
    const EditLine& rLine = rCurPortion.GetLines()[nLine];

    EditPaM aNewPaM( rPaM );
    aNewPaM.SetIndex( rLine.GetEnd() );
@@ -2125,25 +2120,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 );
@@ -2159,9 +2154,9 @@ EditSelection ImpEditEngine::ImpMoveParagraphs( Range aOldPositions, sal_Int32 n
    for (tools::Long i = aOldPositions.Min(); i <= aOldPositions.Max(); i++  )
    {
        // always aOldPositions.Min(), since Remove().
        std::unique_ptr<ParaPortion> pTmpPortion = GetParaPortions().Release(aOldPositions.Min());
        ParaPortion aTmpPortion = GetParaPortions().Remove(aOldPositions.Min());
        aEditDoc.Release( aOldPositions.Min() );
        aTmpPortionList.Append(std::move(pTmpPortion));
        aTmpPortionList.Append(std::move(aTmpPortion));
    }

    sal_Int32 nRealNewPos = pDestPortion ? GetParaPortions().GetPos( pDestPortion ) : GetParaPortions().Count();
@@ -2170,17 +2165,17 @@ EditSelection ImpEditEngine::ImpMoveParagraphs( Range aOldPositions, sal_Int32 n
    sal_Int32 i = 0;
    while( aTmpPortionList.Count() > 0 )
    {
        std::unique_ptr<ParaPortion> pTmpPortion = aTmpPortionList.Release(0);
        ParaPortion aTmpPortion = aTmpPortionList.Remove(0);
        if ( i == 0 )
            aSelection.Min().SetNode( pTmpPortion->GetNode() );
            aSelection.Min().SetNode( aTmpPortion.GetNode() );

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

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

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

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

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

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

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

    // the right node is deleted by EditDoc:ConnectParagraphs().
    if ( GetTextRanger() )
@@ -2292,9 +2286,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* pPP = GetParaPortions()[n];
            pPP->MarkSelectionInvalid( 0 );
            pPP->GetLines().Reset();
            ParaPortion& rPP = GetParaPortions()[n];
            rPP.MarkSelectionInvalid( 0 );
            rPP.GetLines().Reset();
        }
    }

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

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

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

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

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

            if ( GetStatus().DoOnlineSpelling() )
            {
@@ -2748,10 +2737,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'
                pPortion->MarkInvalid( aCurWord.Min().GetIndex(), aLine.getLength() );
                rPortion.MarkInvalid( aCurWord.Min().GetIndex(), aLine.getLength() );
            }
            else
                pPortion->MarkInvalid( aCurPaM.GetIndex(), aLine.getLength() );
                rPortion.MarkInvalid( aCurPaM.GetIndex(), aLine.getLength() );
        }
        if ( nEnd < aText.getLength() )
            aPaM = ImpInsertParaBreak( aPaM );
@@ -2803,9 +2792,8 @@ EditPaM ImpEditEngine::ImpInsertFeature(const EditSelection& rCurSel, const SfxP
    aPaM = aEditDoc.InsertFeature( aPaM, rItem );
    UpdateFields();

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

    TextModified();

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

    ParaPortion* pPortion = FindParaPortion( rPaM.GetNode() );
    OSL_ENSURE( pPortion, "Blind Portion in ImpInsertParaBreak" );
    pPortion->MarkInvalid( rPaM.GetIndex(), 0 );
    ParaPortion& rPortion = FindParaPortion( rPaM.GetNode() );
    rPortion.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( pPortion );
    ParaPortion* pNewPortion = new ParaPortion( aPaM.GetNode() );
    GetParaPortions().Insert(nPos+1, std::unique_ptr<ParaPortion>(pNewPortion));
    ParaAttribsChanged( pNewPortion->GetNode() );
    sal_Int32 nPos = GetParaPortions().GetPos( &rPortion );
    ParaPortion& rNewPortion = GetParaPortions().Insert(nPos+1, ParaPortion(aPaM.GetNode()));
    ParaAttribsChanged( rNewPortion.GetNode() );
    if ( IsCallParaInsertedOrDeleted() )
        GetEditEnginePtr()->ParagraphInserted( nPos+1 );

@@ -2907,7 +2893,7 @@ EditPaM ImpEditEngine::ImpFastInsertParagraph( sal_Int32 nPara )

    aEditDoc.Insert(nPara, pNode);

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

@@ -2999,9 +2985,8 @@ bool ImpEditEngine::UpdateFields()
        if ( bChangesInPara )
        {
            // If possible be more precise when invalidate.
            ParaPortion* pPortion = GetParaPortions()[nPara];
            OSL_ENSURE( pPortion, "NULL-Pointer in Doc" );
            pPortion->MarkSelectionInvalid( 0 );
            ParaPortion& rPortion = GetParaPortions()[nPara];
            rPortion.MarkSelectionInvalid( 0 );
        }
    }
    return bChanges;
@@ -3024,16 +3009,16 @@ tools::Rectangle ImpEditEngine::PaMtoEditCursor( EditPaM aPaM, GetCursorFlags nF
    tools::Long nY = 0;
    for ( sal_Int32 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ )
    {
        ParaPortion* pPortion = GetParaPortions()[nPortion];
        ContentNode* pNode = pPortion->GetNode();
        ParaPortion& rPortion = GetParaPortions()[nPortion];
        ContentNode* pNode = rPortion.GetNode();
        OSL_ENSURE( pNode, "Invalid Node in Portion!" );
        if ( pNode != aPaM.GetNode() )
        {
            nY += pPortion->GetHeight();
            nY += rPortion.GetHeight();
        }
        else
        {
            aEditCursor = GetEditCursor( pPortion, aPaM.GetIndex(), nFlags );
            aEditCursor = GetEditCursor( &rPortion, aPaM.GetIndex(), nFlags );
            aEditCursor.AdjustTop(nY );
            aEditCursor.AdjustBottom(nY );
            return aEditCursor;
@@ -3052,7 +3037,7 @@ EditPaM ImpEditEngine::GetPaM( Point aDocPos, bool bSmart )
    sal_Int32 nPortion;
    for ( nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ )
    {
        ParaPortion* pPortion = GetParaPortions()[nPortion];
        ParaPortion* pPortion = &GetParaPortions()[nPortion];
        const tools::Long nTmpHeight = pPortion->GetHeight();     // should also be correct for !bVisible!
        nY += nTmpHeight;
        if ( nY > aDocPos.Y() )
@@ -3074,12 +3059,12 @@ EditPaM ImpEditEngine::GetPaM( Point aDocPos, bool bSmart )
    }
    // Then search for the last visible:
    nPortion = GetParaPortions().Count()-1;
    while ( nPortion && !GetParaPortions()[nPortion]->IsVisible() )
    while ( nPortion && !GetParaPortions()[nPortion].IsVisible() )
        nPortion--;

    OSL_ENSURE( GetParaPortions()[nPortion]->IsVisible(), "No visible paragraph found: GetPaM" );
    aPaM.SetNode( GetParaPortions()[nPortion]->GetNode() );
    aPaM.SetIndex( GetParaPortions()[nPortion]->GetNode()->Len() );
    OSL_ENSURE( GetParaPortions()[nPortion].IsVisible(), "No visible paragraph found: GetPaM" );
    aPaM.SetNode( GetParaPortions()[nPortion].GetNode() );
    aPaM.SetIndex( GetParaPortions()[nPortion].GetNode()->Len() );
    return aPaM;
}

@@ -3121,20 +3106,19 @@ sal_uInt32 ImpEditEngine::CalcParaWidth( sal_Int32 nPara, bool bIgnoreExtraSpace

    // Over all the paragraphs ...

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


        // On the lines of the paragraph ...

        sal_Int32 nLines = pPortion->GetLines().Count();
        sal_Int32 nLines = rPortion.GetLines().Count();
        for ( sal_Int32 nLine = 0; nLine < nLines; nLine++ )
        {
            EditLine& rLine = pPortion->GetLines()[nLine];
            EditLine& rLine = rPortion.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
@@ -3145,15 +3129,15 @@ sal_uInt32 ImpEditEngine::CalcParaWidth( sal_Int32 nPara, bool bIgnoreExtraSpace
            {
                tools::Long nFI = GetXValue( rLRItem.GetTextFirstLineOffset() );
                nCurWidth -= nFI;
                if ( pPortion->GetBulletX() > nCurWidth )
                if ( rPortion.GetBulletX() > nCurWidth )
                {
                    nCurWidth += nFI;   // LI?
                    if ( pPortion->GetBulletX() > nCurWidth )
                        nCurWidth = pPortion->GetBulletX();
                    if ( rPortion.GetBulletX() > nCurWidth )
                        nCurWidth = rPortion.GetBulletX();
                }
            }
            nCurWidth += GetXValue( rLRItem.GetRight() );
            nCurWidth += CalcLineWidth( pPortion, &rLine, bIgnoreExtraSpace );
            nCurWidth += CalcLineWidth( &rPortion, &rLine, bIgnoreExtraSpace );
            if ( nCurWidth > nMaxWidth )
            {
                nMaxWidth = nCurWidth;
@@ -3232,11 +3216,11 @@ sal_uInt32 ImpEditEngine::CalcTextHeight( sal_uInt32* pHeightNTP )
    sal_uInt32 nPH;
    sal_uInt32 nEmptyHeight = 0;
    for ( sal_Int32 nPortion = 0; nPortion < GetParaPortions().Count(); nPortion++ ) {
        ParaPortion* pPortion = GetParaPortions()[nPortion];
        nPH = pPortion->GetHeight();
        ParaPortion& rPortion = GetParaPortions()[nPortion];
        nPH = rPortion.GetHeight();
        nY += nPH;
        if( pHeightNTP ) {
            if ( pPortion->IsEmpty() )
            if ( rPortion.IsEmpty() )
                nEmptyHeight += nPH;
            else
                nEmptyHeight = 0;
@@ -3363,22 +3347,21 @@ 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* pParaPortion = GetParaPortions()[nPara];
                EditSelection aTmpSelection( EditPaM( pParaPortion->GetNode(), 0 ) );
                ParaPortion& rParaPortion = GetParaPortions()[nPara];
                EditSelection aTmpSelection( EditPaM( rParaPortion.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 195886c..b5a1fe8 100644
--- a/editeng/source/editeng/impedit3.cxx
+++ b/editeng/source/editeng/impedit3.cxx
@@ -354,7 +354,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();
}

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

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

            // InvalidRect set only once...
@@ -415,20 +415,20 @@ void ImpEditEngine::FormatDoc()
            {
                // For Paperwidth 0 (AutoPageSize) it would otherwise be Empty()...
                tools::Long nWidth = std::max( tools::Long(1), ( !IsVertical() ? aPaperSize.Width() : aPaperSize.Height() ) );
                Range aInvRange( GetInvalidYOffsets( pParaPortion ) );
                Range aInvRange( GetInvalidYOffsets( &rParaPortion ) );
                aInvalidRect = tools::Rectangle( Point( 0, nY+aInvRange.Min() ),
                    Size( nWidth, aInvRange.Len() ) );
            }
            else
            {
                aInvalidRect.SetBottom( nY + pParaPortion->GetHeight() );
                aInvalidRect.SetBottom( nY + rParaPortion.GetHeight() );
            }
        }
        else if ( bGrow )
        {
            aInvalidRect.SetBottom( nY + pParaPortion->GetHeight() );
            aInvalidRect.SetBottom( nY + rParaPortion.GetHeight() );
        }
        nY += pParaPortion->GetHeight();
        nY += rParaPortion.GetHeight();
    }

    // One can also get into the formatting through UpdateMode ON=>OFF=>ON...
@@ -531,11 +531,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* pParaPortion = GetParaPortions()[nPara];
            ParaPortion& rParaPortion = GetParaPortions()[nPara];
            SvxAdjust eJustification = GetJustification( nPara );
            if ( eJustification != SvxAdjust::Left )
            {
                pParaPortion->MarkSelectionInvalid( 0 );
                rParaPortion.MarkSelectionInvalid( 0 );
                CreateLines( nPara, 0 );  // 0: For AutoPageSize no TextRange!
            }
        }
@@ -600,28 +600,28 @@ static sal_Int32 ImplCalculateFontIndependentLineSpacing( const sal_Int32 nFontH

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

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

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


    // Fast special treatment for empty paragraphs...

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


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

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


    // Get Paragraph attributes...

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

    bool bRightToLeftPara = IsRightToLeft( nPara );

@@ -653,30 +653,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 = pParaPortion->GetInvalidDiff();
    const sal_Int32 nInvalidStart = pParaPortion->GetInvalidPosStart();
    const short nInvalidDiff = rParaPortion.GetInvalidDiff();
    const sal_Int32 nInvalidStart = rParaPortion.GetInvalidPosStart();
    const sal_Int32 nInvalidEnd =  nInvalidStart + std::abs( nInvalidDiff );

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


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


    sal_Int32 nLine = pParaPortion->GetLines().Count()-1;
    sal_Int32 nLine = rParaPortion.GetLines().Count()-1;
    for ( sal_Int32 nL = 0; nL <= nLine; nL++ )
    {
        EditLine& rLine = pParaPortion->GetLines()[nL];
        EditLine& rLine = rParaPortion.GetLines()[nL];
        if ( rLine.GetEnd() > nRealInvalidStart )  // not nInvalidStart!
        {
            nLine = nL;
@@ -728,20 +728,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 && ( !pParaPortion->IsSimpleInvalid() || ( nInvalidEnd < pNode->Len() ) || ( nInvalidDiff <= 0 ) ) )
    if ( nLine && ( !rParaPortion.IsSimpleInvalid() || ( nInvalidEnd < pNode->Len() ) || ( nInvalidDiff <= 0 ) ) )
        nLine--;

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

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


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

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

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

            tools::Long nTextY = nStartPosY + GetEditCursor( pParaPortion, pLine->GetStart() ).Top();
            tools::Long nTextY = nStartPosY + GetEditCursor( &rParaPortion, pLine->GetStart() ).Top();
            if ( !bSameLineAgain )
            {
                SeekCursor( pNode, nTmpPos+1, aTmpFont );
@@ -902,7 +902,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 = pParaPortion->GetTextPortions().Count();
            const sal_Int32 nTextPortions = rParaPortion.GetTextPortions().Count();
            assert(nTextPortions > 0);
            bContinueLastPortion = (nTmpPortion >= nTextPortions);
            if (bContinueLastPortion)
@@ -920,17 +920,17 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
            }

            nPortionStart = nTmpPos;
            pPortion = &pParaPortion->GetTextPortions()[nTmpPortion];
            pPortion = &rParaPortion.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();
                pParaPortion->GetTextPortions().Remove( nTmpPortion );
                rParaPortion.GetTextPortions().Remove( nTmpPortion );
                if (nTmpPortion && nTmpLen)
                {
                    nTmpPortion--;
                    TextPortion& rPrev = pParaPortion->GetTextPortions()[nTmpPortion];
                    TextPortion& rPrev = rParaPortion.GetTextPortions()[nTmpPortion];
                    DBG_ASSERT( rPrev.GetKind() == PortionKind::TEXT, "Portion?!" );
                    nTmpWidth -= rPrev.GetSize().Width();
                    nTmpPos = nTmpPos - rPrev.GetLen();
@@ -938,8 +938,8 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
                    rPrev.GetSize().setWidth( -1 );
                }

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

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

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

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

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


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

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

@@ -1489,7 +1489,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 = pParaPortion->GetTextPortions()[pLine->GetEndPortion()];
            TextPortion& rTP = rParaPortion.GetTextPortions()[pLine->GetEndPortion()];
            sal_Int32 nPosInArray = pLine->GetEnd()-1-pLine->GetStart();
            tools::Long nNewValue = ( nPosInArray ? pLine->GetCharPosArray()[ nPosInArray-1 ] : 0 ) + n;
            pLine->GetCharPosArray()[ nPosInArray ] = nNewValue;
@@ -1521,7 +1521,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( pParaPortion, pLine, nRemainingSpace );
                    ImpAdjustBlocks( &rParaPortion, pLine, nRemainingSpace );
            }
            break;
            default:
@@ -1555,7 +1555,7 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
        }

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

            // Next line or maybe a new line...
            pLine = nullptr;
            if ( nLine < pParaPortion->GetLines().Count()-1 )
                pLine = &pParaPortion->GetLines()[++nLine];
            if ( nLine < rParaPortion.GetLines().Count()-1 )
                pLine = &rParaPortion.GetLines()[++nLine];
            if ( pLine && ( nIndex >= pNode->Len() ) )
            {
                nDelFromLine = nLine;
@@ -1623,16 +1623,16 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
                if ( nIndex < pNode->Len() )
                {
                    pLine = new EditLine;
                    pParaPortion->GetLines().Insert(++nLine, pLine);
                    rParaPortion.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 );
                    pParaPortion->GetTextPortions().Append(pDummyPortion);
                    rParaPortion.GetTextPortions().Append(pDummyPortion);
                    pLine = new EditLine;
                    pParaPortion->GetLines().Insert(++nLine, pLine);
                    rParaPortion.GetLines().Insert(++nLine, pLine);
                    bForceOneRun = true;
                    bProcessingEmptyLine = true;
                }
@@ -1649,16 +1649,16 @@ bool ImpEditEngine::CreateLines( sal_Int32 nPara, sal_uInt32 nStartPosY )
    }   // while ( Index < Len )

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

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

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

    pBuf.reset();

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

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

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

    FormatFullDoc();
@@ -2960,7 +2960,7 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po
    tools::Long nFirstVisYPos = - pOutDev->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* >( pOutDev->GetExtOutDevData() );

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

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

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

        const tools::Long nParaHeight = pPortion->GetHeight();
        if ( pPortion->IsVisible() && (
        const tools::Long nParaHeight = rPortion.GetHeight();
        if ( rPortion.IsVisible() && (
                ( !IsVertical() && ( ( aStartPos.Y() + nParaHeight ) > aClipRect.Top() ) ) ||
                ( IsVertical() && IsTopToBottom() && ( ( aStartPos.X() - nParaHeight ) < aClipRect.Right() ) ) ||
                ( IsVertical() && !IsTopToBottom() && ( ( aStartPos.X() + nParaHeight ) > aClipRect.Left() ) ) ) )
@@ -3009,31 +3008,31 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po

            // Over the lines of the paragraph...

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

            bool bEndOfParagraphWritten(false);

            if ( !IsVertical() )
                aStartPos.AdjustY(pPortion->GetFirstLineOffset() );
                aStartPos.AdjustY(rPortion.GetFirstLineOffset() );
            else
            {
                if( IsTopToBottom() )
                    aStartPos.AdjustX( -(pPortion->GetFirstLineOffset()) );
                    aStartPos.AdjustX( -(rPortion.GetFirstLineOffset()) );
                else
                    aStartPos.AdjustX(pPortion->GetFirstLineOffset() );
                    aStartPos.AdjustX(rPortion.GetFirstLineOffset() );
            }

            const Point aParaStart( aStartPos );

            const SvxLineSpacingItem& rLSItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_SBL );
            const SvxLineSpacingItem& rLSItem = rPortion.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 = &pPortion->GetLines()[nLine];
                const EditLine* const pLine = &rPortion.GetLines()[nLine];
                assert( pLine && "NULL-Pointer in the line iterator in UpdateViews" );
                sal_Int32 nIndex = pLine->GetStart();
                aTmpPos = aStartPos;
@@ -3092,10 +3091,10 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po

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

                        const tools::Long nPortionXOffset = GetPortionXOffset( pPortion, pLine, nPortion );
                        const tools::Long nPortionXOffset = GetPortionXOffset( &rPortion, pLine, nPortion );
                        if ( !IsVertical() )
                        {
                            aTmpPos.setX( aStartPos.X() + nPortionXOffset );
@@ -3124,7 +3123,7 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po
                            case PortionKind::FIELD:
                            case PortionKind::HYPHENATOR:
                            {
                                SeekCursor( pPortion->GetNode(), nIndex+1, aTmpFont, pOutDev );
                                SeekCursor( rPortion.GetNode(), nIndex+1, aTmpFont, pOutDev );

                                bool bDrawFrame = false;

@@ -3172,7 +3171,7 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po

                                if ( rTextPortion.GetKind() == PortionKind::TEXT )
                                {
                                    aText = pPortion->GetNode()->GetString();
                                    aText = rPortion.GetNode()->GetString();
                                    nTextStart = nIndex;
                                    nTextLen = rTextPortion.GetLen();
                                    pDXArray = pLine->GetCharPosArray().data() + (nIndex - pLine->GetStart());
@@ -3291,7 +3290,7 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po
                                }
                                else if ( rTextPortion.GetKind() == PortionKind::FIELD )
                                {
                                    const EditCharAttrib* pAttr = pPortion->GetNode()->GetCharAttribs().FindFeature(nIndex);
                                    const EditCharAttrib* pAttr = rPortion.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();
@@ -3403,7 +3402,7 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po

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

                                        if(pWrongs && !pWrongs->empty())
                                        {
@@ -3450,7 +3449,7 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, tools::Rectangle aClipRect, Po

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

                                        if(pFieldItem)
@@ -3462,7 +3461,7 @@ void ImpEditEngine::Paint( OutputDevice* pOutDev, 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(pPortion->GetNode(), nIndex + 1)));
                                    const lang::Locale aLocale(GetLocale(EditPaM(rPortion.GetNode(), nIndex + 1)));

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

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

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

            if ( !aStatus.IsOutliner() )
            {
                const SvxULSpaceItem& rULItem = pPortion->GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
                const SvxULSpaceItem& rULItem = rPortion.GetNode()->GetContentAttribs().GetItem( EE_PARA_ULSPACE );
                tools::Long nUL = GetYValue( rULItem.GetLower() );
                if ( !IsVertical() )
                    aStartPos.AdjustY(nUL );
@@ -3909,7 +3908,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, std::make_unique<ParaPortion>( pNode ));
    GetParaPortions().Insert(nPos, ParaPortion( pNode ));
    aEditDoc.Insert(nPos, pNode);
    if ( IsCallParaInsertedOrDeleted() )
        GetEditEnginePtr()->ParagraphInserted( nPos );
@@ -4045,18 +4044,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 )
    {
        pTmpPortion = GetParaPortions()[nFirstInvPara-1];
        pTmpPortion->MarkInvalid( pTmpPortion->GetNode()->Len(), 0 );
        ParaPortion& rTmpPortion = GetParaPortions()[nFirstInvPara-1];
        rTmpPortion.MarkInvalid( rTmpPortion.GetNode()->Len(), 0 );
        rTmpPortion.ResetHeight();
    }
    else
    {
        pTmpPortion = GetParaPortions()[0];
        pTmpPortion->MarkSelectionInvalid( 0 );
        ParaPortion& rTmpPortion = GetParaPortions()[0];
        rTmpPortion.MarkSelectionInvalid( 0 );
        rTmpPortion.ResetHeight();
    }
    pTmpPortion->ResetHeight();
}

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

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

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

    return pPortion;
}
@@ -4132,7 +4128,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);
@@ -4215,7 +4211,7 @@ void ImpEditEngine::FormatAndUpdate( 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 );
    }
@@ -4634,8 +4630,8 @@ void ImpEditEngine::ImplUpdateOverflowingParaNum(sal_uInt32 nPaperHeight)
    sal_uInt32 nPH;

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

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

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

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

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

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

        if ( nNode == nStartNode )
        {
            nStartPos = aSel.Min().GetIndex();
            nStartPortion = pParaPortion->GetTextPortions().FindPortion( nStartPos, nPortionStart );
            nStartPortion = rParaPortion.GetTextPortions().FindPortion( nStartPos, nPortionStart );
            if ( nStartPos != 0 )
            {
                aAttribItems.Clear();
@@ -580,14 +579,14 @@ ErrCode ImpEditEngine::WriteRTF( SvStream& rOutput, EditSelection aSel )
        if ( nNode == nEndNode ) // can also be == nStart!
        {
            nEndPos = aSel.Max().GetIndex();
            nEndPortion = pParaPortion->GetTextPortions().FindPortion( nEndPos, nPortionStart );
            nEndPortion = rParaPortion.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 = pParaPortion->GetTextPortions()[n];
            const TextPortion& rTextPortion = rParaPortion.GetTextPortions()[n];
            if ( n < nStartPortion )
            {
                nIndex = nIndex + rTextPortion.GetLen();
@@ -1022,8 +1021,8 @@ std::unique_ptr<EditTextObject> ImpEditEngine::CreateTextObject( EditSelection a

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

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

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

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

            // The lines
            nCount = pParaPortion->GetLines().Count();
            nCount = rParaPortion.GetLines().Count();
            for ( n = 0; n < nCount; n++ )
            {
                const EditLine& rLine = pParaPortion->GetLines()[n];
                const EditLine& rLine = rParaPortion.GetLines()[n];
                EditLine* pNew = rLine.Clone();
                pX->aLines.Append(pNew);
            }
#ifdef DBG_UTIL
            sal_uInt16 nTest;
            int nTPLen = 0, nTxtLen = 0;
            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!" );
            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!" );
#endif
        }
    }
@@ -1213,9 +1212,8 @@ EditSelection ImpEditEngine::InsertTextObject( const EditTextObject& rTextObject

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

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

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

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

#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
@@ -1293,41 +1291,40 @@ EditSelection ImpEditEngine::InsertTextObject( const EditTextObject& rTextObject
            if ( bNewContent && bUsePortionInfo )
            {
                const XParaPortion& rXP = (*pPortionInfo)[n];
                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
                ParaPortion& rParaPortion = GetParaPortions()[ nPara ];
                rParaPortion.nHeight = rXP.nHeight;
                rParaPortion.nFirstLineOffset = rXP.nFirstLineOffset;
                rParaPortion.bForceRepaint = true;
                rParaPortion.SetValid();   // Do not format

                // The Text Portions
                pParaPortion->GetTextPortions().Reset();
                rParaPortion.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 );
                    pParaPortion->GetTextPortions().Insert(_n, pNew);
                    rParaPortion.GetTextPortions().Insert(_n, pNew);
                }

                // The lines
                pParaPortion->GetLines().Reset();
                rParaPortion.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!
                    pParaPortion->GetLines().Insert(m, pNew);
                    rParaPortion.GetLines().Insert(m, pNew);
                }
#ifdef DBG_UTIL
                sal_uInt16 nTest;
                int nTPLen = 0, nTxtLen = 0;
                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() ), "InsertBinTextObject: ParaPortion not completely formatted!" );
                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() ), "InsertBinTextObject: ParaPortion not completely formatted!" );
#endif
            }
        }
@@ -2945,8 +2942,8 @@ EditSelection ImpEditEngine::TransliterateText( const EditSelection& rSelection,
                    aNewSel.Max().SetIndex( aNewSel.Max().GetIndex() + nDiffs );

                sal_Int32 nSelNode = aEditDoc.GetPos( rData.aSelection.Min().GetNode() );
                ParaPortion* pParaPortion = GetParaPortions()[nSelNode];
                pParaPortion->MarkSelectionInvalid( rData.nStart );
                ParaPortion& rParaPortion = GetParaPortions()[nSelNode];
                rParaPortion.MarkSelectionInvalid( rData.nStart );
            }
        }
    }
diff --git a/editeng/source/editeng/impedit5.cxx b/editeng/source/editeng/impedit5.cxx
index 3db8903..0213349 100644
--- a/editeng/source/editeng/impedit5.cxx
+++ b/editeng/source/editeng/impedit5.cxx
@@ -520,7 +520,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* pPortion = GetParaPortions()[nNode];
        ParaPortion& rPortion = 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!
@@ -562,14 +562,14 @@ void ImpEditEngine::SetAttribs( EditSelection aSel, const SfxItemSet& rSet, SetA

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

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