editeng/Library_editeng.mk             |    1 
 editeng/inc/ContentNode.hxx            |    9 
 editeng/source/editeng/ContentNode.cxx | 1000 +++++++++++++++++++++++++++++++++
 editeng/source/editeng/editdoc.cxx     |  984 --------------------------------
 solenv/clang-format/excludelist        |    1 
 5 files changed, 1005 insertions(+), 990 deletions(-)

New commits:
commit 5c198a8d1345a5f658a46085de9cdd76d49a959e
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Sun Dec 24 16:37:58 2023 +0900
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Fri Dec 29 12:38:11 2023 +0100

    editeng: simplify and remove unneded const. of ContentNode & co
    
    ContentNode, CharAttribList, ContentAttribs constructors and
    destructors can be simplified and in some cases removed (if they
    are empty).
    
    Change-Id: Id5b1d4c1934a9b0b6e0ed8a7fe2af0d41ce4b4fb
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161356
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/editeng/inc/ContentNode.hxx b/editeng/inc/ContentNode.hxx
index d89612ddeac8..391953d7f4ae 100644
--- a/editeng/inc/ContentNode.hxx
+++ b/editeng/inc/ContentNode.hxx
@@ -37,7 +37,7 @@ class SvxTabStop;
 class ContentAttribs
 {
 private:
-    SfxStyleSheet* mpStyle;
+    SfxStyleSheet* mpStyle = nullptr;
     SfxItemSetFixed<EE_PARA_START, EE_CHAR_END> maAttribSet;
 
 public:
@@ -68,12 +68,9 @@ public:
 private:
     AttribsType maAttribs;
     SvxFont maDefFont; // faster than ever from the pool!
-    bool mbHasEmptyAttribs;
+    bool mbHasEmptyAttribs = false;
 
 public:
-    CharAttribList();
-    ~CharAttribList();
-
     void dumpAsXml(xmlTextWriterPtr pWriter) const;
 
     void DeleteEmptyAttribs();
@@ -122,7 +119,7 @@ private:
 public:
     ContentNode(SfxItemPool& rItemPool);
     ContentNode(const OUString& rStr, const ContentAttribs& rContentAttribs);
-    ~ContentNode();
+
     ContentNode(const ContentNode&) = delete;
     ContentNode& operator=(const ContentNode&) = delete;
 
diff --git a/editeng/source/editeng/ContentNode.cxx 
b/editeng/source/editeng/ContentNode.cxx
index 16d6a1ed808b..0cc3a72da65c 100644
--- a/editeng/source/editeng/ContentNode.cxx
+++ b/editeng/source/editeng/ContentNode.cxx
@@ -40,10 +40,6 @@ ContentNode::ContentNode( const OUString& rStr, const 
ContentAttribs& rContentAt
 {
 }
 
-ContentNode::~ContentNode()
-{
-}
-
 void ContentNode::ExpandAttribs( sal_Int32 nIndex, sal_Int32 nNew )
 {
     if ( !nNew )
@@ -653,12 +649,10 @@ void ContentNode::checkAndDeleteEmptyAttribs() const
 }
 
 ContentAttribs::ContentAttribs( SfxItemPool& rPool )
-: mpStyle(nullptr)
-, maAttribSet( rPool )
+    : maAttribSet(rPool)
 {
 }
 
-
 SvxTabStop ContentAttribs::FindTabStop( sal_Int32 nCurPos, sal_uInt16 nDefTab )
 {
     const SvxTabStopItem& rTabs = GetItem( EE_PARA_TABS );
@@ -741,15 +735,6 @@ struct LessByStart
 
 }
 
-CharAttribList::CharAttribList()
-: mbHasEmptyAttribs(false)
-{
-}
-
-CharAttribList::~CharAttribList()
-{
-}
-
 void CharAttribList::InsertAttrib( EditCharAttrib* pAttrib )
 {
 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
commit 62aee46df1f8e4b863e2927e0b9d3b6bcd270008
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Sun Dec 24 16:33:46 2023 +0900
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Fri Dec 29 12:38:04 2023 +0100

    editeng: move source of ContentNode & co. to own sourcefile
    
    Move ContentNode, CharAttribList, ContentAttribs methods to own
    source class.
    
    Change-Id: Idd1371430ecaf36431de763dc4e3e3978ba60641
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/161355
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/editeng/Library_editeng.mk b/editeng/Library_editeng.mk
index 7f7f3581b62f..e0834b96f983 100644
--- a/editeng/Library_editeng.mk
+++ b/editeng/Library_editeng.mk
@@ -50,6 +50,7 @@ $(eval $(call gb_Library_add_exception_objects,editeng,\
 endif
 
 $(eval $(call gb_Library_add_exception_objects,editeng,\
+    editeng/source/editeng/ContentNode \
     editeng/source/editeng/editattr \
     editeng/source/editeng/editdata \
     editeng/source/editeng/editdbg \
diff --git a/editeng/source/editeng/ContentNode.cxx 
b/editeng/source/editeng/ContentNode.cxx
new file mode 100644
index 000000000000..16d6a1ed808b
--- /dev/null
+++ b/editeng/source/editeng/ContentNode.cxx
@@ -0,0 +1,1015 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <ContentNode.hxx>
+#include <editeng/tstpitem.hxx>
+#include "impedit.hxx"
+
+#include <rtl/ustrbuf.hxx>
+#include <osl/diagnose.h>
+#include <libxml/xmlwriter.h>
+
+#include <memory>
+#include <set>
+
+ContentNode::ContentNode( SfxItemPool& rPool )
+    : maContentAttribs( rPool )
+{
+}
+
+ContentNode::ContentNode( const OUString& rStr, const ContentAttribs& 
rContentAttribs )
+    : maString(rStr)
+    , maContentAttribs(rContentAttribs)
+{
+}
+
+ContentNode::~ContentNode()
+{
+}
+
+void ContentNode::ExpandAttribs( sal_Int32 nIndex, sal_Int32 nNew )
+{
+    if ( !nNew )
+        return;
+
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+    CharAttribList::DbgCheckAttribs(maCharAttribList);
+#endif
+
+    // Since features are treated differently than normal character attributes,
+    // but can also affect the order of the start list.    // In every if ..., 
 in the next (n) opportunities due to bFeature or
+    // an existing special case, must (n-1) opportunities be provided with
+    // bResort. The most likely possibility receives no bResort, so that is
+    // not sorted anew when all attributes are the same.
+    bool bResort = false;
+    bool bExpandedEmptyAtIndexNull = false;
+
+    std::size_t nAttr = 0;
+    CharAttribList::AttribsType& rAttribs = maCharAttribList.GetAttribs();
+    EditCharAttrib* pAttrib = GetAttrib(rAttribs, nAttr);
+    while ( pAttrib )
+    {
+        if ( pAttrib->GetEnd() >= nIndex )
+        {
+            // Move all attributes behind the insertion point...
+            if ( pAttrib->GetStart() > nIndex )
+            {
+                pAttrib->MoveForward( nNew );
+            }
+            // 0: Expand empty attribute, if at insertion point
+            else if ( pAttrib->IsEmpty() )
+            {
+                // Do not check Index, an empty one could only be there
+                // When later checking it anyhow:
+                //   Special case: Start == 0; AbsLen == 1, nNew = 1
+                // => Expand, because of paragraph break!
+                // Start <= nIndex, End >= nIndex => Start=End=nIndex!
+//              if ( pAttrib->GetStart() == nIndex )
+                pAttrib->Expand( nNew );
+                bResort = true;
+                if ( pAttrib->GetStart() == 0 )
+                    bExpandedEmptyAtIndexNull = true;
+            }
+            // 1: Attribute starts before, goes to index ...
+            else if ( pAttrib->GetEnd() == nIndex ) // Start must be before
+            {
+                // Only expand when there is no feature
+                // and if not in exclude list!
+                // Otherwise, a UL will go on until a new ULDB, expanding both
+//              if ( !pAttrib->IsFeature() && !rExclList.FindAttrib( 
pAttrib->Which() ) )
+                if ( !pAttrib->IsFeature() && 
!maCharAttribList.FindEmptyAttrib( pAttrib->Which(), nIndex ) )
+                {
+                    if ( !pAttrib->IsEdge() )
+                        pAttrib->Expand( nNew );
+                }
+                else
+                    bResort = true;
+            }
+            // 2: Attribute starts before, goes past the Index...
+            else if ( ( pAttrib->GetStart() < nIndex ) && ( pAttrib->GetEnd() 
> nIndex ) )
+            {
+                DBG_ASSERT( !pAttrib->IsFeature(), "Large Feature?!" );
+                pAttrib->Expand( nNew );
+            }
+            // 3: Attribute starts on index...
+            else if ( pAttrib->GetStart() == nIndex )
+            {
+                if ( pAttrib->IsFeature() )
+                {
+                    pAttrib->MoveForward( nNew );
+                    bResort = true;
+                }
+                else
+                {
+                    bool bExpand = false;
+                    if ( nIndex == 0 )
+                    {
+                        bExpand = true;
+                        if( bExpandedEmptyAtIndexNull )
+                        {
+                            // Check if this kind of attribute was empty and 
expanded here...
+                            sal_uInt16 nW = pAttrib->GetItem()->Which();
+                            for ( std::size_t nA = 0; nA < nAttr; nA++ )
+                            {
+                                const EditCharAttrib& r = 
*maCharAttribList.GetAttribs()[nA];
+                                if ( ( r.GetStart() == 0 ) && ( 
r.GetItem()->Which() == nW ) )
+                                {
+                                    bExpand = false;
+                                    break;
+                                }
+                            }
+
+                        }
+                    }
+                    if ( bExpand )
+                    {
+                        pAttrib->Expand( nNew );
+                        bResort = true;
+                    }
+                    else
+                    {
+                        pAttrib->MoveForward( nNew );
+                    }
+                }
+            }
+        }
+
+        if ( pAttrib->IsEdge() )
+            pAttrib->SetEdge(false);
+
+        DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), 
"Expand: FeaturesLen != 1" );
+
+        DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Expand: 
Attribute distorted!" );
+        DBG_ASSERT( ( pAttrib->GetEnd() <= Len() ), "Expand: Attribute larger 
than paragraph!" );
+        if ( pAttrib->IsEmpty() )
+        {
+            OSL_FAIL( "Empty Attribute after ExpandAttribs?" );
+            bResort = true;
+            rAttribs.erase(rAttribs.begin()+nAttr);
+        }
+        else
+        {
+            ++nAttr;
+        }
+        pAttrib = GetAttrib(rAttribs, nAttr);
+    }
+
+    if ( bResort )
+        maCharAttribList.ResortAttribs();
+
+    if (mpWrongList)
+    {
+        bool bSep = ( maString[ nIndex ] == ' ' ) || IsFeature( nIndex );
+        mpWrongList->TextInserted( nIndex, nNew, bSep );
+    }
+
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+    CharAttribList::DbgCheckAttribs(maCharAttribList);
+#endif
+}
+
+void ContentNode::CollapseAttribs( sal_Int32 nIndex, sal_Int32 nDeleted )
+{
+    if ( !nDeleted )
+        return;
+
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+    CharAttribList::DbgCheckAttribs(maCharAttribList);
+#endif
+
+    // Since features are treated differently than normal character attributes,
+    // but can also affect the order of the start list
+    bool bResort = false;
+    sal_Int32 nEndChanges = nIndex+nDeleted;
+
+    std::size_t nAttr = 0;
+    CharAttribList::AttribsType& rAttribs = maCharAttribList.GetAttribs();
+    EditCharAttrib* pAttrib = GetAttrib(rAttribs, nAttr);
+    while ( pAttrib )
+    {
+        bool bDelAttr = false;
+        if ( pAttrib->GetEnd() >= nIndex )
+        {
+            // Move all Attribute behind the insert point...
+            if ( pAttrib->GetStart() >= nEndChanges )
+            {
+                pAttrib->MoveBackward( nDeleted );
+            }
+            // 1. Delete Internal attributes...
+            else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() 
<= nEndChanges ) )
+            {
+                // Special case: Attribute covers the area exactly
+                // => keep as empty Attribute.
+                if ( !pAttrib->IsFeature() && ( pAttrib->GetStart() == nIndex 
) && ( pAttrib->GetEnd() == nEndChanges ) )
+                {
+                    pAttrib->GetEnd() = nIndex; // empty
+                    bResort = true;
+                }
+                else
+                    bDelAttr = true;
+            }
+            // 2. Attribute starts earlier, ends inside or behind it ...
+            else if ( ( pAttrib->GetStart() <= nIndex ) && ( pAttrib->GetEnd() 
> nIndex ) )
+            {
+                DBG_ASSERT( !pAttrib->IsFeature(), "Collapsing Feature!" );
+                if ( pAttrib->GetEnd() <= nEndChanges ) // ends inside
+                    pAttrib->GetEnd() = nIndex;
+                else
+                    pAttrib->Collaps( nDeleted );       // ends behind
+            }
+            // 3. Attribute starts inside, ending behind ...
+            else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() 
> nEndChanges ) )
+            {
+                // Features not allowed to expand!
+                if ( pAttrib->IsFeature() )
+                {
+                    pAttrib->MoveBackward( nDeleted );
+                    bResort = true;
+                }
+                else
+                {
+                    pAttrib->GetStart() = nEndChanges;
+                    pAttrib->MoveBackward( nDeleted );
+                }
+            }
+        }
+        DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), 
"Expand: FeaturesLen != 1" );
+
+        DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Collapse: 
Attribute distorted!" );
+        DBG_ASSERT( ( pAttrib->GetEnd() <= Len()) || bDelAttr, "Collapse: 
Attribute larger than paragraph!" );
+        if ( bDelAttr )
+        {
+            bResort = true;
+            rAttribs.erase(rAttribs.begin()+nAttr);
+        }
+        else
+        {
+            if ( pAttrib->IsEmpty() )
+                maCharAttribList.SetHasEmptyAttribs(true);
+            nAttr++;
+        }
+
+        pAttrib = GetAttrib(rAttribs, nAttr);
+    }
+
+    if ( bResort )
+        maCharAttribList.ResortAttribs();
+
+    if (mpWrongList)
+        mpWrongList->TextDeleted(nIndex, nDeleted);
+
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+    CharAttribList::DbgCheckAttribs(maCharAttribList);
+#endif
+}
+
+void ContentNode::CopyAndCutAttribs( ContentNode* pPrevNode, SfxItemPool& 
rPool, bool bKeepEndingAttribs )
+{
+    assert(pPrevNode);
+
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+    CharAttribList::DbgCheckAttribs(maCharAttribList);
+    CharAttribList::DbgCheckAttribs(pPrevNode->maCharAttribList);
+#endif
+
+    sal_Int32 nCut = pPrevNode->Len();
+
+    std::size_t nAttr = 0;
+    CharAttribList::AttribsType& rPrevAttribs = 
pPrevNode->GetCharAttribs().GetAttribs();
+    EditCharAttrib* pAttrib = GetAttrib(rPrevAttribs, nAttr);
+    while ( pAttrib )
+    {
+        if ( pAttrib->GetEnd() < nCut )
+        {
+            // remain unchanged...
+            nAttr++;
+        }
+        else if ( pAttrib->GetEnd() == nCut )
+        {
+            // must be copied as an empty attributes.
+            if ( bKeepEndingAttribs && !pAttrib->IsFeature() && 
!maCharAttribList.FindAttrib( pAttrib->GetItem()->Which(), 0 ) )
+            {
+                EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, 
*(pAttrib->GetItem()), 0, 0 );
+                assert(pNewAttrib);
+                maCharAttribList.InsertAttrib( pNewAttrib );
+            }
+            nAttr++;
+        }
+        else if ( pAttrib->IsInside( nCut ) || ( !nCut && !pAttrib->GetStart() 
&& !pAttrib->IsFeature() ) )
+        {
+            // If cut is done right at the front then the attribute must be
+            // kept! Has to be copied and changed.
+            EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, 
*(pAttrib->GetItem()), 0, pAttrib->GetEnd()-nCut );
+            assert(pNewAttrib);
+            maCharAttribList.InsertAttrib( pNewAttrib );
+            pAttrib->GetEnd() = nCut;
+            nAttr++;
+        }
+        else
+        {
+            // Move all attributes in the current node (this)
+            CharAttribList::AttribsType::iterator it = rPrevAttribs.begin() + 
nAttr;
+            maCharAttribList.InsertAttrib(it->release());
+            rPrevAttribs.erase(it);
+            pAttrib->MoveBackward( nCut );
+        }
+        pAttrib = GetAttrib(rPrevAttribs, nAttr);
+    }
+
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+    CharAttribList::DbgCheckAttribs(maCharAttribList);
+    CharAttribList::DbgCheckAttribs(pPrevNode->maCharAttribList);
+#endif
+}
+
+void ContentNode::AppendAttribs( ContentNode* pNextNode )
+{
+    assert(pNextNode);
+
+    sal_Int32 nNewStart = maString.getLength();
+
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+    CharAttribList::DbgCheckAttribs(maCharAttribList);
+    CharAttribList::DbgCheckAttribs(pNextNode->maCharAttribList);
+#endif
+
+    std::size_t nAttr = 0;
+    CharAttribList::AttribsType& rNextAttribs = 
pNextNode->GetCharAttribs().GetAttribs();
+    EditCharAttrib* pAttrib = GetAttrib(rNextAttribs, nAttr);
+    while ( pAttrib )
+    {
+        // Move all attributes in the current node (this)
+        bool bMelted = false;
+        if ( ( pAttrib->GetStart() == 0 ) && ( !pAttrib->IsFeature() ) )
+        {
+            // Attributes can possibly be summarized as:
+            std::size_t nTmpAttr = 0;
+            EditCharAttrib* pTmpAttrib = GetAttrib( 
maCharAttribList.GetAttribs(), nTmpAttr );
+            while ( !bMelted && pTmpAttrib )
+            {
+                ++nTmpAttr;
+                if ( pTmpAttrib->GetEnd() == nNewStart )
+                {
+                    if (pTmpAttrib->Which() == pAttrib->Which())
+                    {
+                        // prevent adding 2 0-length attributes at same 
position
+                        if ((*(pTmpAttrib->GetItem()) == *(pAttrib->GetItem()))
+                                || (0 == pAttrib->GetLen()))
+                        {
+                            pTmpAttrib->GetEnd() =
+                                pTmpAttrib->GetEnd() + pAttrib->GetLen();
+                            rNextAttribs.erase(rNextAttribs.begin()+nAttr);
+                            // Unsubscribe from the pool?!
+                            bMelted = true;
+                        }
+                        else if (0 == pTmpAttrib->GetLen())
+                        {
+                            --nTmpAttr; // to cancel earlier increment...
+                            maCharAttribList.Remove(nTmpAttr);
+                        }
+                    }
+                }
+                pTmpAttrib = GetAttrib( maCharAttribList.GetAttribs(), 
nTmpAttr );
+            }
+        }
+
+        if ( !bMelted )
+        {
+            pAttrib->GetStart() = pAttrib->GetStart() + nNewStart;
+            pAttrib->GetEnd() = pAttrib->GetEnd() + nNewStart;
+            CharAttribList::AttribsType::iterator it = rNextAttribs.begin() + 
nAttr;
+            maCharAttribList.InsertAttrib(it->release());
+            rNextAttribs.erase(it);
+        }
+        pAttrib = GetAttrib(rNextAttribs, nAttr);
+    }
+    // For the Attributes that just moved over:
+    rNextAttribs.clear();
+
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+    CharAttribList::DbgCheckAttribs(maCharAttribList);
+    CharAttribList::DbgCheckAttribs(pNextNode->maCharAttribList);
+#endif
+}
+
+void ContentNode::CreateDefFont()
+{
+    // First use the information from the style ...
+    SfxStyleSheet* pS = maContentAttribs.GetStyleSheet();
+    if ( pS )
+        CreateFont( GetCharAttribs().GetDefFont(), pS->GetItemSet() );
+
+    // ... then iron out the hard paragraph formatting...
+    CreateFont( GetCharAttribs().GetDefFont(),
+        GetContentAttribs().GetItems(), pS == nullptr );
+}
+
+void ContentNode::SetStyleSheet( SfxStyleSheet* pS, const SvxFont& 
rFontFromStyle )
+{
+    maContentAttribs.SetStyleSheet( pS );
+
+
+    // First use the information from the style ...
+    GetCharAttribs().GetDefFont() = rFontFromStyle;
+    // ... then iron out the hard paragraph formatting...
+    CreateFont( GetCharAttribs().GetDefFont(),
+                GetContentAttribs().GetItems(), pS == nullptr );
+}
+
+void ContentNode::SetStyleSheet( SfxStyleSheet* pS, bool bRecalcFont )
+{
+    maContentAttribs.SetStyleSheet( pS );
+    if ( bRecalcFont )
+        CreateDefFont();
+}
+
+bool ContentNode::IsFeature( sal_Int32 nPos ) const
+{
+    return maString[nPos] == CH_FEATURE;
+}
+
+sal_Int32 ContentNode::Len() const
+{
+    return maString.getLength();
+}
+
+sal_Int32 ContentNode::GetExpandedLen() const
+{
+    sal_Int32 nLen = maString.getLength();
+
+    // Fields can be longer than the placeholder in the Node
+    const CharAttribList::AttribsType& rAttrs = GetCharAttribs().GetAttribs();
+    for (sal_Int32 nAttr = rAttrs.size(); nAttr; )
+    {
+        const EditCharAttrib& rAttr = *rAttrs[--nAttr];
+        if (rAttr.Which() == EE_FEATURE_FIELD)
+        {
+            nLen += static_cast<const 
EditCharAttribField&>(rAttr).GetFieldValue().getLength();
+            --nLen; // Standalone, to avoid corner cases when previous 
getLength() returns 0
+        }
+    }
+
+    return nLen;
+}
+
+OUString ContentNode::GetExpandedText(sal_Int32 nStartPos, sal_Int32 nEndPos) 
const
+{
+    if ( nEndPos < 0 || nEndPos > Len() )
+        nEndPos = Len();
+
+    DBG_ASSERT( nStartPos <= nEndPos, "Start and End reversed?" );
+
+    sal_Int32 nIndex = nStartPos;
+    OUStringBuffer aStr(256);
+    const EditCharAttrib* pNextFeature = GetCharAttribs().FindFeature( nIndex 
);
+    while ( nIndex < nEndPos )
+    {
+        sal_Int32 nEnd = nEndPos;
+        if ( pNextFeature && ( pNextFeature->GetStart() < nEnd ) )
+            nEnd = pNextFeature->GetStart();
+        else
+            pNextFeature = nullptr;   // Feature does not interest the below
+
+        DBG_ASSERT( nEnd >= nIndex, "End in front of the index?" );
+        //!! beware of sub string length  of -1
+        if (nEnd > nIndex)
+            aStr.append( GetString().subView(nIndex, nEnd - nIndex) );
+
+        if ( pNextFeature )
+        {
+            switch ( pNextFeature->GetItem()->Which() )
+            {
+                case EE_FEATURE_TAB:    aStr.append( " " );
+                break;
+                case EE_FEATURE_LINEBR: aStr.append( "\x0A" );
+                break;
+                case EE_FEATURE_FIELD:
+                    aStr.append( static_cast<const 
EditCharAttribField*>(pNextFeature)->GetFieldValue() );
+                break;
+                default:    OSL_FAIL( "What feature?" );
+            }
+            pNextFeature = GetCharAttribs().FindFeature( ++nEnd );
+        }
+        nIndex = nEnd;
+    }
+    return aStr.makeStringAndClear();
+}
+
+void ContentNode::UnExpandPosition( sal_Int32 &rPos, bool bBiasStart )
+{
+    sal_Int32 nOffset = 0;
+
+    const CharAttribList::AttribsType& rAttrs = GetCharAttribs().GetAttribs();
+    for (size_t nAttr = 0; nAttr < rAttrs.size(); ++nAttr )
+    {
+        const EditCharAttrib& rAttr = *rAttrs[nAttr];
+        assert (!(nAttr < rAttrs.size() - 1) ||
+                rAttrs[nAttr]->GetStart() <= rAttrs[nAttr + 1]->GetStart());
+
+        nOffset = rAttr.GetStart();
+
+        if (nOffset >= rPos) // happens after the position
+            return;
+
+        if (rAttr.Which() == EE_FEATURE_FIELD)
+        {
+            sal_Int32 nChunk = static_cast<const 
EditCharAttribField&>(rAttr).GetFieldValue().getLength();
+            nChunk--; // Character representing the field in the string
+
+            if (nOffset + nChunk >= rPos) // we're inside the field
+            {
+                if (bBiasStart)
+                    rPos = rAttr.GetStart();
+                else
+                    rPos = rAttr.GetEnd();
+                return;
+            }
+            // Adjust for the position
+            rPos -= nChunk;
+        }
+    }
+    assert (rPos <= Len());
+}
+
+/*
+ * Fields are represented by a single character in the underlying string
+ * and/or selection, however, they can be expanded to the full value of
+ * the field. When we're dealing with selection / offsets however we need
+ * to deal in character positions inside the real (unexpanded) string.
+ * This method maps us back to character offsets.
+ */
+void ContentNode::UnExpandPositions( sal_Int32 &rStartPos, sal_Int32 &rEndPos )
+{
+    UnExpandPosition( rStartPos, true );
+    UnExpandPosition( rEndPos, false );
+}
+
+void ContentNode::SetChar(sal_Int32 nPos, sal_Unicode c)
+{
+    maString = maString.replaceAt(nPos, 1, rtl::OUStringChar(c));
+}
+
+void ContentNode::Insert(std::u16string_view rStr, sal_Int32 nPos)
+{
+    maString = maString.replaceAt(nPos, 0, rStr);
+}
+
+void ContentNode::Append(std::u16string_view rStr)
+{
+    maString += rStr;
+}
+
+void ContentNode::Erase(sal_Int32 nPos)
+{
+    maString = maString.copy(0, nPos);
+}
+
+void ContentNode::Erase(sal_Int32 nPos, sal_Int32 nCount)
+{
+    maString = maString.replaceAt(nPos, nCount, u"");
+}
+
+OUString ContentNode::Copy(sal_Int32 nPos) const
+{
+    return maString.copy(nPos);
+}
+
+OUString ContentNode::Copy(sal_Int32 nPos, sal_Int32 nCount) const
+{
+    return maString.copy(nPos, nCount);
+}
+
+sal_Unicode ContentNode::GetChar(sal_Int32 nPos) const
+{
+    return maString[nPos];
+}
+
+void ContentNode::EnsureWrongList()
+{
+    if (!mpWrongList)
+        CreateWrongList();
+}
+
+WrongList* ContentNode::GetWrongList()
+{
+    return mpWrongList.get();
+}
+
+const WrongList* ContentNode::GetWrongList() const
+{
+    return mpWrongList.get();
+}
+
+void ContentNode::SetWrongList( WrongList* p )
+{
+    mpWrongList.reset(p);
+}
+
+void ContentNode::CreateWrongList()
+{
+    SAL_WARN_IF( mpWrongList && !mpWrongList->empty(), "editeng", "WrongList 
already exist!");
+    if (!mpWrongList || !mpWrongList->empty())
+        mpWrongList.reset(new WrongList);
+}
+
+void ContentNode::DestroyWrongList()
+{
+    mpWrongList.reset();
+}
+
+void ContentNode::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+    (void)xmlTextWriterStartElement(pWriter, BAD_CAST("ContentNode"));
+    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("maString"), 
BAD_CAST(maString.toUtf8().getStr()));
+    maContentAttribs.dumpAsXml(pWriter);
+    maCharAttribList.dumpAsXml(pWriter);
+    (void)xmlTextWriterEndElement(pWriter);
+}
+
+void ContentNode::checkAndDeleteEmptyAttribs() const
+{
+    // Delete empty attributes, but only if paragraph is not empty!
+    if (GetCharAttribs().HasEmptyAttribs() && Len())
+    {
+        const_cast<ContentNode*>(this)->GetCharAttribs().DeleteEmptyAttribs();
+    }
+}
+
+ContentAttribs::ContentAttribs( SfxItemPool& rPool )
+: mpStyle(nullptr)
+, maAttribSet( rPool )
+{
+}
+
+
+SvxTabStop ContentAttribs::FindTabStop( sal_Int32 nCurPos, sal_uInt16 nDefTab )
+{
+    const SvxTabStopItem& rTabs = GetItem( EE_PARA_TABS );
+    for ( sal_uInt16 i = 0; i < rTabs.Count(); i++ )
+    {
+        const SvxTabStop& rTab = rTabs[i];
+        if ( rTab.GetTabPos() > nCurPos  )
+            return rTab;
+    }
+
+    // if there's a default tab size defined for this item use that instead
+    if (rTabs.GetDefaultDistance())
+        nDefTab = rTabs.GetDefaultDistance();
+
+    // Determine DefTab ...
+    SvxTabStop aTabStop;
+    const sal_Int32 x = nCurPos / nDefTab + 1;
+    aTabStop.GetTabPos() = nDefTab * x;
+    return aTabStop;
+}
+
+void ContentAttribs::SetStyleSheet( SfxStyleSheet* pS )
+{
+    bool bStyleChanged = ( mpStyle != pS );
+    mpStyle = pS;
+    // Only when other style sheet, not when current style sheet modified
+    if ( !(mpStyle && bStyleChanged) )
+        return;
+
+    // Selectively remove the attributes from the paragraph formatting
+    // which are specified in the style, so that the attributes of the
+    // style can have an affect.
+    const SfxItemSet& rStyleAttribs = mpStyle->GetItemSet();
+    for ( sal_uInt16 nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ )
+    {
+        // Don't change bullet on/off
+        if ( ( nWhich != EE_PARA_BULLETSTATE ) && ( 
rStyleAttribs.GetItemState( nWhich ) == SfxItemState::SET ) )
+            maAttribSet.ClearItem( nWhich );
+    }
+}
+
+const SfxPoolItem& ContentAttribs::GetItem( sal_uInt16 nWhich ) const
+{
+    // Hard paragraph attributes take precedence!
+    const SfxItemSet* pTakeFrom = &maAttribSet;
+    if ( mpStyle && ( maAttribSet.GetItemState( nWhich, false ) != 
SfxItemState::SET  ) )
+        pTakeFrom = &mpStyle->GetItemSet();
+
+    return pTakeFrom->Get( nWhich );
+}
+
+bool ContentAttribs::HasItem( sal_uInt16 nWhich ) const
+{
+    bool bHasItem = false;
+    if ( maAttribSet.GetItemState( nWhich, false ) == SfxItemState::SET  )
+        bHasItem = true;
+    else if ( mpStyle && mpStyle->GetItemSet().GetItemState( nWhich ) == 
SfxItemState::SET )
+        bHasItem = true;
+
+    return bHasItem;
+}
+
+void ContentAttribs::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+    (void)xmlTextWriterStartElement(pWriter, BAD_CAST("ContentAttribs"));
+    (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("style"), "%s", 
mpStyle->GetName().toUtf8().getStr());
+    maAttribSet.dumpAsXml(pWriter);
+    (void)xmlTextWriterEndElement(pWriter);
+}
+
+namespace {
+
+struct LessByStart
+{
+    bool operator() (const std::unique_ptr<EditCharAttrib>& left, const 
std::unique_ptr<EditCharAttrib>& right) const
+    {
+        return left->GetStart() < right->GetStart();
+    }
+};
+
+}
+
+CharAttribList::CharAttribList()
+: mbHasEmptyAttribs(false)
+{
+}
+
+CharAttribList::~CharAttribList()
+{
+}
+
+void CharAttribList::InsertAttrib( EditCharAttrib* pAttrib )
+{
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+// optimize: binary search?    !
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+    // Maybe just simply iterate backwards:
+    // The most common and critical case: Attributes are already sorted
+    // (InsertTextObject!) binary search would not be optimal here.
+    // => Would bring something!
+
+    const sal_Int32 nStart = pAttrib->GetStart(); // may be better for 
Comp.Opt.
+
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+    CharAttribList::DbgCheckAttribs(*this);
+#endif
+
+    if ( pAttrib->IsEmpty() )
+        mbHasEmptyAttribs = true;
+
+    bool bInsert(true);
+    for (sal_Int32 i = 0, n = maAttribs.size(); i < n; ++i)
+    {
+        const EditCharAttrib& rCurAttrib = *maAttribs[i];
+        if (rCurAttrib.GetStart() > nStart)
+        {
+            maAttribs.insert(maAttribs.begin()+i, 
std::unique_ptr<EditCharAttrib>(pAttrib));
+            bInsert = false;
+            break;
+        }
+    }
+
+    if (bInsert) maAttribs.push_back(std::unique_ptr<EditCharAttrib>(pAttrib));
+
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+    CharAttribList::DbgCheckAttribs(*this);
+#endif
+}
+
+void CharAttribList::ResortAttribs()
+{
+    std::sort(maAttribs.begin(), maAttribs.end(), LessByStart());
+
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+    CharAttribList::DbgCheckAttribs(*this);
+#endif
+}
+
+void CharAttribList::OptimizeRanges()
+{
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+    CharAttribList::DbgCheckAttribs(*this);
+#endif
+    for (sal_Int32 i = 0; i < static_cast<sal_Int32>(maAttribs.size()); ++i)
+    {
+        EditCharAttrib& rAttr = *maAttribs[i];
+        for (sal_Int32 nNext = i+1; nNext < 
static_cast<sal_Int32>(maAttribs.size()); ++nNext)
+        {
+            EditCharAttrib& rNext = *maAttribs[nNext];
+            if (!rAttr.IsFeature() && rNext.GetStart() == rAttr.GetEnd() && 
rNext.Which() == rAttr.Which())
+            {
+                if (*rNext.GetItem() == *rAttr.GetItem())
+                {
+                    rAttr.GetEnd() = rNext.GetEnd();
+                    maAttribs.erase(maAttribs.begin()+nNext);
+                }
+                break;  // only 1 attr with same which can start here.
+            }
+            else if (rNext.GetStart() > rAttr.GetEnd())
+            {
+                break;
+            }
+        }
+    }
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+    CharAttribList::DbgCheckAttribs(*this);
+#endif
+}
+
+sal_Int32 CharAttribList::Count() const
+{
+    return maAttribs.size();
+}
+
+const EditCharAttrib* CharAttribList::FindAttrib( sal_uInt16 nWhich, sal_Int32 
nPos ) const
+{
+    // Backwards, if one ends where the next starts.
+    // => The starting one is the valid one ...
+    AttribsType::const_reverse_iterator it = std::find_if(maAttribs.rbegin(), 
maAttribs.rend(),
+        [&nWhich, &nPos](const AttribsType::value_type& rxAttr) {
+            return rxAttr->Which() == nWhich && rxAttr->IsIn(nPos); });
+    if (it != maAttribs.rend())
+    {
+        const EditCharAttrib& rAttr = **it;
+        return &rAttr;
+    }
+    return nullptr;
+}
+
+EditCharAttrib* CharAttribList::FindAttrib( sal_uInt16 nWhich, sal_Int32 nPos )
+{
+    // Backwards, if one ends where the next starts.
+    // => The starting one is the valid one ...
+    AttribsType::reverse_iterator it = std::find_if(maAttribs.rbegin(), 
maAttribs.rend(),
+        [&nWhich, &nPos](AttribsType::value_type& rxAttr) {
+            return rxAttr->Which() == nWhich && rxAttr->IsIn(nPos); });
+    if (it != maAttribs.rend())
+    {
+        EditCharAttrib& rAttr = **it;
+        return &rAttr;
+    }
+    return nullptr;
+}
+
+const EditCharAttrib* CharAttribList::FindNextAttrib( sal_uInt16 nWhich, 
sal_Int32 nFromPos ) const
+{
+    assert(nWhich);
+    for (auto const& attrib : maAttribs)
+    {
+        const EditCharAttrib& rAttr = *attrib;
+        if (rAttr.GetStart() >= nFromPos && rAttr.Which() == nWhich)
+            return &rAttr;
+    }
+    return nullptr;
+}
+
+bool CharAttribList::HasAttrib( sal_Int32 nStartPos, sal_Int32 nEndPos ) const
+{
+    return std::any_of(maAttribs.rbegin(), maAttribs.rend(),
+        [&nStartPos, &nEndPos](const AttribsType::value_type& rxAttr) {
+            return rxAttr->GetStart() < nEndPos && rxAttr->GetEnd() > 
nStartPos; });
+}
+
+
+namespace {
+
+class FindByAddress
+{
+    const EditCharAttrib* mpAttr;
+public:
+    explicit FindByAddress(const EditCharAttrib* p) : mpAttr(p) {}
+    bool operator() (const std::unique_ptr<EditCharAttrib>& r) const
+    {
+        return r.get() == mpAttr;
+    }
+};
+
+}
+
+void CharAttribList::Remove(const EditCharAttrib* p)
+{
+    AttribsType::iterator it = std::find_if(maAttribs.begin(), 
maAttribs.end(), FindByAddress(p));
+    if (it != maAttribs.end())
+        maAttribs.erase(it);
+}
+
+void CharAttribList::Remove(sal_Int32 nPos)
+{
+    if (nPos >= static_cast<sal_Int32>(maAttribs.size()))
+        return;
+
+    maAttribs.erase(maAttribs.begin()+nPos);
+}
+
+void CharAttribList::SetHasEmptyAttribs(bool b)
+{
+    mbHasEmptyAttribs = b;
+}
+
+bool CharAttribList::HasBoundingAttrib( sal_Int32 nBound ) const
+{
+    // Backwards, if one ends where the next starts.
+    // => The starting one is the valid one ...
+    AttribsType::const_reverse_iterator it = maAttribs.rbegin(), itEnd = 
maAttribs.rend();
+    for (; it != itEnd; ++it)
+    {
+        const EditCharAttrib& rAttr = **it;
+        if (rAttr.GetEnd() < nBound)
+            return false;
+
+        if (rAttr.GetStart() == nBound || rAttr.GetEnd() == nBound)
+            return true;
+    }
+    return false;
+}
+
+EditCharAttrib* CharAttribList::FindEmptyAttrib( sal_uInt16 nWhich, sal_Int32 
nPos )
+{
+    if ( !mbHasEmptyAttribs )
+        return nullptr;
+
+    for (const std::unique_ptr<EditCharAttrib>& rAttr : maAttribs)
+    {
+        if (rAttr->GetStart() == nPos && rAttr->GetEnd() == nPos && 
rAttr->Which() == nWhich)
+            return rAttr.get();
+    }
+    return nullptr;
+}
+
+namespace {
+
+class FindByStartPos
+{
+    sal_Int32 mnPos;
+public:
+    explicit FindByStartPos(sal_Int32 nPos) : mnPos(nPos) {}
+    bool operator() (const std::unique_ptr<EditCharAttrib>& r) const
+    {
+        return r->GetStart() >= mnPos;
+    }
+};
+
+}
+
+const EditCharAttrib* CharAttribList::FindFeature( sal_Int32 nPos ) const
+{
+    // First, find the first attribute that starts at or after specified 
position.
+    AttribsType::const_iterator it =
+        std::find_if(maAttribs.begin(), maAttribs.end(), FindByStartPos(nPos));
+
+    if (it == maAttribs.end())
+        // All attributes are before the specified position.
+        return nullptr;
+
+    // And find the first attribute with feature.
+    it = std::find_if(it, maAttribs.end(), [](const 
std::unique_ptr<EditCharAttrib>& aAttrib) { return aAttrib->IsFeature(); } );
+    return it == maAttribs.end() ? nullptr : it->get();
+}
+
+void CharAttribList::DeleteEmptyAttribs()
+{
+    std::erase_if(maAttribs, [](const std::unique_ptr<EditCharAttrib>& 
aAttrib) { return aAttrib->IsEmpty(); } );
+    mbHasEmptyAttribs = false;
+}
+
+#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
+void CharAttribList::DbgCheckAttribs(CharAttribList const& rAttribs)
+{
+    std::set<std::pair<sal_Int32, sal_uInt16>> zero_set;
+    for (const std::unique_ptr<EditCharAttrib>& rAttr : rAttribs.maAttribs)
+    {
+        assert(rAttr->GetStart() <= rAttr->GetEnd());
+        assert(!rAttr->IsFeature() || rAttr->GetLen() == 1);
+        if (0 == rAttr->GetLen())
+        {
+            // not sure if 0-length attributes allowed at all in non-empty 
para?
+            assert(zero_set.insert(std::make_pair(rAttr->GetStart(), 
rAttr->Which())).second && "duplicate 0-length attribute detected");
+        }
+    }
+    CheckOrderedList(rAttribs.GetAttribs());
+}
+#endif
+
+void CharAttribList::dumpAsXml(xmlTextWriterPtr pWriter) const
+{
+    (void)xmlTextWriterStartElement(pWriter, BAD_CAST("CharAttribList"));
+    for (auto const & i : maAttribs) {
+        i->dumpAsXml(pWriter);
+    }
+    (void)xmlTextWriterEndElement(pWriter);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/editeng/source/editeng/editdoc.cxx 
b/editeng/source/editeng/editdoc.cxx
index 8bac8f2cf67b..0d6ce0f315c4 100644
--- a/editeng/source/editeng/editdoc.cxx
+++ b/editeng/source/editeng/editdoc.cxx
@@ -1164,706 +1164,6 @@ bool operator != ( const EditPaM& r1, const EditPaM& r2 
)
     return !( r1 == r2 );
 }
 
-ContentNode::ContentNode( SfxItemPool& rPool )
-    : maContentAttribs( rPool )
-{
-}
-
-ContentNode::ContentNode( const OUString& rStr, const ContentAttribs& 
rContentAttribs )
-    : maString(rStr)
-    , maContentAttribs(rContentAttribs)
-{
-}
-
-ContentNode::~ContentNode()
-{
-}
-
-void ContentNode::ExpandAttribs( sal_Int32 nIndex, sal_Int32 nNew )
-{
-    if ( !nNew )
-        return;
-
-#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
-    CharAttribList::DbgCheckAttribs(maCharAttribList);
-#endif
-
-    // Since features are treated differently than normal character attributes,
-    // but can also affect the order of the start list.    // In every if ..., 
 in the next (n) opportunities due to bFeature or
-    // an existing special case, must (n-1) opportunities be provided with
-    // bResort. The most likely possibility receives no bResort, so that is
-    // not sorted anew when all attributes are the same.
-    bool bResort = false;
-    bool bExpandedEmptyAtIndexNull = false;
-
-    std::size_t nAttr = 0;
-    CharAttribList::AttribsType& rAttribs = maCharAttribList.GetAttribs();
-    EditCharAttrib* pAttrib = GetAttrib(rAttribs, nAttr);
-    while ( pAttrib )
-    {
-        if ( pAttrib->GetEnd() >= nIndex )
-        {
-            // Move all attributes behind the insertion point...
-            if ( pAttrib->GetStart() > nIndex )
-            {
-                pAttrib->MoveForward( nNew );
-            }
-            // 0: Expand empty attribute, if at insertion point
-            else if ( pAttrib->IsEmpty() )
-            {
-                // Do not check Index, an empty one could only be there
-                // When later checking it anyhow:
-                //   Special case: Start == 0; AbsLen == 1, nNew = 1
-                // => Expand, because of paragraph break!
-                // Start <= nIndex, End >= nIndex => Start=End=nIndex!
-//              if ( pAttrib->GetStart() == nIndex )
-                pAttrib->Expand( nNew );
-                bResort = true;
-                if ( pAttrib->GetStart() == 0 )
-                    bExpandedEmptyAtIndexNull = true;
-            }
-            // 1: Attribute starts before, goes to index ...
-            else if ( pAttrib->GetEnd() == nIndex ) // Start must be before
-            {
-                // Only expand when there is no feature
-                // and if not in exclude list!
-                // Otherwise, a UL will go on until a new ULDB, expanding both
-//              if ( !pAttrib->IsFeature() && !rExclList.FindAttrib( 
pAttrib->Which() ) )
-                if ( !pAttrib->IsFeature() && 
!maCharAttribList.FindEmptyAttrib( pAttrib->Which(), nIndex ) )
-                {
-                    if ( !pAttrib->IsEdge() )
-                        pAttrib->Expand( nNew );
-                }
-                else
-                    bResort = true;
-            }
-            // 2: Attribute starts before, goes past the Index...
-            else if ( ( pAttrib->GetStart() < nIndex ) && ( pAttrib->GetEnd() 
> nIndex ) )
-            {
-                DBG_ASSERT( !pAttrib->IsFeature(), "Large Feature?!" );
-                pAttrib->Expand( nNew );
-            }
-            // 3: Attribute starts on index...
-            else if ( pAttrib->GetStart() == nIndex )
-            {
-                if ( pAttrib->IsFeature() )
-                {
-                    pAttrib->MoveForward( nNew );
-                    bResort = true;
-                }
-                else
-                {
-                    bool bExpand = false;
-                    if ( nIndex == 0 )
-                    {
-                        bExpand = true;
-                        if( bExpandedEmptyAtIndexNull )
-                        {
-                            // Check if this kind of attribute was empty and 
expanded here...
-                            sal_uInt16 nW = pAttrib->GetItem()->Which();
-                            for ( std::size_t nA = 0; nA < nAttr; nA++ )
-                            {
-                                const EditCharAttrib& r = 
*maCharAttribList.GetAttribs()[nA];
-                                if ( ( r.GetStart() == 0 ) && ( 
r.GetItem()->Which() == nW ) )
-                                {
-                                    bExpand = false;
-                                    break;
-                                }
-                            }
-
-                        }
-                    }
-                    if ( bExpand )
-                    {
-                        pAttrib->Expand( nNew );
-                        bResort = true;
-                    }
-                    else
-                    {
-                        pAttrib->MoveForward( nNew );
-                    }
-                }
-            }
-        }
-
-        if ( pAttrib->IsEdge() )
-            pAttrib->SetEdge(false);
-
-        DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), 
"Expand: FeaturesLen != 1" );
-
-        DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Expand: 
Attribute distorted!" );
-        DBG_ASSERT( ( pAttrib->GetEnd() <= Len() ), "Expand: Attribute larger 
than paragraph!" );
-        if ( pAttrib->IsEmpty() )
-        {
-            OSL_FAIL( "Empty Attribute after ExpandAttribs?" );
-            bResort = true;
-            rAttribs.erase(rAttribs.begin()+nAttr);
-        }
-        else
-        {
-            ++nAttr;
-        }
-        pAttrib = GetAttrib(rAttribs, nAttr);
-    }
-
-    if ( bResort )
-        maCharAttribList.ResortAttribs();
-
-    if (mpWrongList)
-    {
-        bool bSep = ( maString[ nIndex ] == ' ' ) || IsFeature( nIndex );
-        mpWrongList->TextInserted( nIndex, nNew, bSep );
-    }
-
-#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
-    CharAttribList::DbgCheckAttribs(maCharAttribList);
-#endif
-}
-
-void ContentNode::CollapseAttribs( sal_Int32 nIndex, sal_Int32 nDeleted )
-{
-    if ( !nDeleted )
-        return;
-
-#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
-    CharAttribList::DbgCheckAttribs(maCharAttribList);
-#endif
-
-    // Since features are treated differently than normal character attributes,
-    // but can also affect the order of the start list
-    bool bResort = false;
-    sal_Int32 nEndChanges = nIndex+nDeleted;
-
-    std::size_t nAttr = 0;
-    CharAttribList::AttribsType& rAttribs = maCharAttribList.GetAttribs();
-    EditCharAttrib* pAttrib = GetAttrib(rAttribs, nAttr);
-    while ( pAttrib )
-    {
-        bool bDelAttr = false;
-        if ( pAttrib->GetEnd() >= nIndex )
-        {
-            // Move all Attribute behind the insert point...
-            if ( pAttrib->GetStart() >= nEndChanges )
-            {
-                pAttrib->MoveBackward( nDeleted );
-            }
-            // 1. Delete Internal attributes...
-            else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() 
<= nEndChanges ) )
-            {
-                // Special case: Attribute covers the area exactly
-                // => keep as empty Attribute.
-                if ( !pAttrib->IsFeature() && ( pAttrib->GetStart() == nIndex 
) && ( pAttrib->GetEnd() == nEndChanges ) )
-                {
-                    pAttrib->GetEnd() = nIndex; // empty
-                    bResort = true;
-                }
-                else
-                    bDelAttr = true;
-            }
-            // 2. Attribute starts earlier, ends inside or behind it ...
-            else if ( ( pAttrib->GetStart() <= nIndex ) && ( pAttrib->GetEnd() 
> nIndex ) )
-            {
-                DBG_ASSERT( !pAttrib->IsFeature(), "Collapsing Feature!" );
-                if ( pAttrib->GetEnd() <= nEndChanges ) // ends inside
-                    pAttrib->GetEnd() = nIndex;
-                else
-                    pAttrib->Collaps( nDeleted );       // ends behind
-            }
-            // 3. Attribute starts inside, ending behind ...
-            else if ( ( pAttrib->GetStart() >= nIndex ) && ( pAttrib->GetEnd() 
> nEndChanges ) )
-            {
-                // Features not allowed to expand!
-                if ( pAttrib->IsFeature() )
-                {
-                    pAttrib->MoveBackward( nDeleted );
-                    bResort = true;
-                }
-                else
-                {
-                    pAttrib->GetStart() = nEndChanges;
-                    pAttrib->MoveBackward( nDeleted );
-                }
-            }
-        }
-        DBG_ASSERT( !pAttrib->IsFeature() || ( pAttrib->GetLen() == 1 ), 
"Expand: FeaturesLen != 1" );
-
-        DBG_ASSERT( pAttrib->GetStart() <= pAttrib->GetEnd(), "Collapse: 
Attribute distorted!" );
-        DBG_ASSERT( ( pAttrib->GetEnd() <= Len()) || bDelAttr, "Collapse: 
Attribute larger than paragraph!" );
-        if ( bDelAttr )
-        {
-            bResort = true;
-            rAttribs.erase(rAttribs.begin()+nAttr);
-        }
-        else
-        {
-            if ( pAttrib->IsEmpty() )
-                maCharAttribList.SetHasEmptyAttribs(true);
-            nAttr++;
-        }
-
-        pAttrib = GetAttrib(rAttribs, nAttr);
-    }
-
-    if ( bResort )
-        maCharAttribList.ResortAttribs();
-
-    if (mpWrongList)
-        mpWrongList->TextDeleted(nIndex, nDeleted);
-
-#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
-    CharAttribList::DbgCheckAttribs(maCharAttribList);
-#endif
-}
-
-void ContentNode::CopyAndCutAttribs( ContentNode* pPrevNode, SfxItemPool& 
rPool, bool bKeepEndingAttribs )
-{
-    assert(pPrevNode);
-
-#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
-    CharAttribList::DbgCheckAttribs(maCharAttribList);
-    CharAttribList::DbgCheckAttribs(pPrevNode->maCharAttribList);
-#endif
-
-    sal_Int32 nCut = pPrevNode->Len();
-
-    std::size_t nAttr = 0;
-    CharAttribList::AttribsType& rPrevAttribs = 
pPrevNode->GetCharAttribs().GetAttribs();
-    EditCharAttrib* pAttrib = GetAttrib(rPrevAttribs, nAttr);
-    while ( pAttrib )
-    {
-        if ( pAttrib->GetEnd() < nCut )
-        {
-            // remain unchanged...
-            nAttr++;
-        }
-        else if ( pAttrib->GetEnd() == nCut )
-        {
-            // must be copied as an empty attributes.
-            if ( bKeepEndingAttribs && !pAttrib->IsFeature() && 
!maCharAttribList.FindAttrib( pAttrib->GetItem()->Which(), 0 ) )
-            {
-                EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, 
*(pAttrib->GetItem()), 0, 0 );
-                assert(pNewAttrib);
-                maCharAttribList.InsertAttrib( pNewAttrib );
-            }
-            nAttr++;
-        }
-        else if ( pAttrib->IsInside( nCut ) || ( !nCut && !pAttrib->GetStart() 
&& !pAttrib->IsFeature() ) )
-        {
-            // If cut is done right at the front then the attribute must be
-            // kept! Has to be copied and changed.
-            EditCharAttrib* pNewAttrib = MakeCharAttrib( rPool, 
*(pAttrib->GetItem()), 0, pAttrib->GetEnd()-nCut );
-            assert(pNewAttrib);
-            maCharAttribList.InsertAttrib( pNewAttrib );
-            pAttrib->GetEnd() = nCut;
-            nAttr++;
-        }
-        else
-        {
-            // Move all attributes in the current node (this)
-            CharAttribList::AttribsType::iterator it = rPrevAttribs.begin() + 
nAttr;
-            maCharAttribList.InsertAttrib(it->release());
-            rPrevAttribs.erase(it);
-            pAttrib->MoveBackward( nCut );
-        }
-        pAttrib = GetAttrib(rPrevAttribs, nAttr);
-    }
-
-#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
-    CharAttribList::DbgCheckAttribs(maCharAttribList);
-    CharAttribList::DbgCheckAttribs(pPrevNode->maCharAttribList);
-#endif
-}
-
-void ContentNode::AppendAttribs( ContentNode* pNextNode )
-{
-    assert(pNextNode);
-
-    sal_Int32 nNewStart = maString.getLength();
-
-#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
-    CharAttribList::DbgCheckAttribs(maCharAttribList);
-    CharAttribList::DbgCheckAttribs(pNextNode->maCharAttribList);
-#endif
-
-    std::size_t nAttr = 0;
-    CharAttribList::AttribsType& rNextAttribs = 
pNextNode->GetCharAttribs().GetAttribs();
-    EditCharAttrib* pAttrib = GetAttrib(rNextAttribs, nAttr);
-    while ( pAttrib )
-    {
-        // Move all attributes in the current node (this)
-        bool bMelted = false;
-        if ( ( pAttrib->GetStart() == 0 ) && ( !pAttrib->IsFeature() ) )
-        {
-            // Attributes can possibly be summarized as:
-            std::size_t nTmpAttr = 0;
-            EditCharAttrib* pTmpAttrib = GetAttrib( 
maCharAttribList.GetAttribs(), nTmpAttr );
-            while ( !bMelted && pTmpAttrib )
-            {
-                ++nTmpAttr;
-                if ( pTmpAttrib->GetEnd() == nNewStart )
-                {
-                    if (pTmpAttrib->Which() == pAttrib->Which())
-                    {
-                        // prevent adding 2 0-length attributes at same 
position
-                        if ((*(pTmpAttrib->GetItem()) == *(pAttrib->GetItem()))
-                                || (0 == pAttrib->GetLen()))
-                        {
-                            pTmpAttrib->GetEnd() =
-                                pTmpAttrib->GetEnd() + pAttrib->GetLen();
-                            rNextAttribs.erase(rNextAttribs.begin()+nAttr);
-                            // Unsubscribe from the pool?!
-                            bMelted = true;
-                        }
-                        else if (0 == pTmpAttrib->GetLen())
-                        {
-                            --nTmpAttr; // to cancel earlier increment...
-                            maCharAttribList.Remove(nTmpAttr);
-                        }
-                    }
-                }
-                pTmpAttrib = GetAttrib( maCharAttribList.GetAttribs(), 
nTmpAttr );
-            }
-        }
-
-        if ( !bMelted )
-        {
-            pAttrib->GetStart() = pAttrib->GetStart() + nNewStart;
-            pAttrib->GetEnd() = pAttrib->GetEnd() + nNewStart;
-            CharAttribList::AttribsType::iterator it = rNextAttribs.begin() + 
nAttr;
-            maCharAttribList.InsertAttrib(it->release());
-            rNextAttribs.erase(it);
-        }
-        pAttrib = GetAttrib(rNextAttribs, nAttr);
-    }
-    // For the Attributes that just moved over:
-    rNextAttribs.clear();
-
-#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
-    CharAttribList::DbgCheckAttribs(maCharAttribList);
-    CharAttribList::DbgCheckAttribs(pNextNode->maCharAttribList);
-#endif
-}
-
-void ContentNode::CreateDefFont()
-{
-    // First use the information from the style ...
-    SfxStyleSheet* pS = maContentAttribs.GetStyleSheet();
-    if ( pS )
-        CreateFont( GetCharAttribs().GetDefFont(), pS->GetItemSet() );
-
-    // ... then iron out the hard paragraph formatting...
-    CreateFont( GetCharAttribs().GetDefFont(),
-        GetContentAttribs().GetItems(), pS == nullptr );
-}
-
-void ContentNode::SetStyleSheet( SfxStyleSheet* pS, const SvxFont& 
rFontFromStyle )
-{
-    maContentAttribs.SetStyleSheet( pS );
-
-
-    // First use the information from the style ...
-    GetCharAttribs().GetDefFont() = rFontFromStyle;
-    // ... then iron out the hard paragraph formatting...
-    CreateFont( GetCharAttribs().GetDefFont(),
-                GetContentAttribs().GetItems(), pS == nullptr );
-}
-
-void ContentNode::SetStyleSheet( SfxStyleSheet* pS, bool bRecalcFont )
-{
-    maContentAttribs.SetStyleSheet( pS );
-    if ( bRecalcFont )
-        CreateDefFont();
-}
-
-bool ContentNode::IsFeature( sal_Int32 nPos ) const
-{
-    return maString[nPos] == CH_FEATURE;
-}
-
-sal_Int32 ContentNode::Len() const
-{
-    return maString.getLength();
-}
-
-sal_Int32 ContentNode::GetExpandedLen() const
-{
-    sal_Int32 nLen = maString.getLength();
-
-    // Fields can be longer than the placeholder in the Node
-    const CharAttribList::AttribsType& rAttrs = GetCharAttribs().GetAttribs();
-    for (sal_Int32 nAttr = rAttrs.size(); nAttr; )
-    {
-        const EditCharAttrib& rAttr = *rAttrs[--nAttr];
-        if (rAttr.Which() == EE_FEATURE_FIELD)
-        {
-            nLen += static_cast<const 
EditCharAttribField&>(rAttr).GetFieldValue().getLength();
-            --nLen; // Standalone, to avoid corner cases when previous 
getLength() returns 0
-        }
-    }
-
-    return nLen;
-}
-
-OUString ContentNode::GetExpandedText(sal_Int32 nStartPos, sal_Int32 nEndPos) 
const
-{
-    if ( nEndPos < 0 || nEndPos > Len() )
-        nEndPos = Len();
-
-    DBG_ASSERT( nStartPos <= nEndPos, "Start and End reversed?" );
-
-    sal_Int32 nIndex = nStartPos;
-    OUStringBuffer aStr(256);
-    const EditCharAttrib* pNextFeature = GetCharAttribs().FindFeature( nIndex 
);
-    while ( nIndex < nEndPos )
-    {
-        sal_Int32 nEnd = nEndPos;
-        if ( pNextFeature && ( pNextFeature->GetStart() < nEnd ) )
-            nEnd = pNextFeature->GetStart();
-        else
-            pNextFeature = nullptr;   // Feature does not interest the below
-
-        DBG_ASSERT( nEnd >= nIndex, "End in front of the index?" );
-        //!! beware of sub string length  of -1
-        if (nEnd > nIndex)
-            aStr.append( GetString().subView(nIndex, nEnd - nIndex) );
-
-        if ( pNextFeature )
-        {
-            switch ( pNextFeature->GetItem()->Which() )
-            {
-                case EE_FEATURE_TAB:    aStr.append( " " );
-                break;
-                case EE_FEATURE_LINEBR: aStr.append( "\x0A" );
-                break;
-                case EE_FEATURE_FIELD:
-                    aStr.append( static_cast<const 
EditCharAttribField*>(pNextFeature)->GetFieldValue() );
-                break;
-                default:    OSL_FAIL( "What feature?" );
-            }
-            pNextFeature = GetCharAttribs().FindFeature( ++nEnd );
-        }
-        nIndex = nEnd;
-    }
-    return aStr.makeStringAndClear();
-}
-
-void ContentNode::UnExpandPosition( sal_Int32 &rPos, bool bBiasStart )
-{
-    sal_Int32 nOffset = 0;
-
-    const CharAttribList::AttribsType& rAttrs = GetCharAttribs().GetAttribs();
-    for (size_t nAttr = 0; nAttr < rAttrs.size(); ++nAttr )
-    {
-        const EditCharAttrib& rAttr = *rAttrs[nAttr];
-        assert (!(nAttr < rAttrs.size() - 1) ||
-                rAttrs[nAttr]->GetStart() <= rAttrs[nAttr + 1]->GetStart());
-
-        nOffset = rAttr.GetStart();
-
-        if (nOffset >= rPos) // happens after the position
-            return;
-
-        if (rAttr.Which() == EE_FEATURE_FIELD)
-        {
-            sal_Int32 nChunk = static_cast<const 
EditCharAttribField&>(rAttr).GetFieldValue().getLength();
-            nChunk--; // Character representing the field in the string
-
-            if (nOffset + nChunk >= rPos) // we're inside the field
-            {
-                if (bBiasStart)
-                    rPos = rAttr.GetStart();
-                else
-                    rPos = rAttr.GetEnd();
-                return;
-            }
-            // Adjust for the position
-            rPos -= nChunk;
-        }
-    }
-    assert (rPos <= Len());
-}
-
-/*
- * Fields are represented by a single character in the underlying string
- * and/or selection, however, they can be expanded to the full value of
- * the field. When we're dealing with selection / offsets however we need
- * to deal in character positions inside the real (unexpanded) string.
- * This method maps us back to character offsets.
- */
-void ContentNode::UnExpandPositions( sal_Int32 &rStartPos, sal_Int32 &rEndPos )
-{
-    UnExpandPosition( rStartPos, true );
-    UnExpandPosition( rEndPos, false );
-}
-
-void ContentNode::SetChar(sal_Int32 nPos, sal_Unicode c)
-{
-    maString = maString.replaceAt(nPos, 1, rtl::OUStringChar(c));
-}
-
-void ContentNode::Insert(std::u16string_view rStr, sal_Int32 nPos)
-{
-    maString = maString.replaceAt(nPos, 0, rStr);
-}
-
-void ContentNode::Append(std::u16string_view rStr)
-{
-    maString += rStr;
-}
-
-void ContentNode::Erase(sal_Int32 nPos)
-{
-    maString = maString.copy(0, nPos);
-}
-
-void ContentNode::Erase(sal_Int32 nPos, sal_Int32 nCount)
-{
-    maString = maString.replaceAt(nPos, nCount, u"");
-}
-
-OUString ContentNode::Copy(sal_Int32 nPos) const
-{
-    return maString.copy(nPos);
-}
-
-OUString ContentNode::Copy(sal_Int32 nPos, sal_Int32 nCount) const
-{
-    return maString.copy(nPos, nCount);
-}
-
-sal_Unicode ContentNode::GetChar(sal_Int32 nPos) const
-{
-    return maString[nPos];
-}
-
-void ContentNode::EnsureWrongList()
-{
-    if (!mpWrongList)
-        CreateWrongList();
-}
-
-WrongList* ContentNode::GetWrongList()
-{
-    return mpWrongList.get();
-}
-
-const WrongList* ContentNode::GetWrongList() const
-{
-    return mpWrongList.get();
-}
-
-void ContentNode::SetWrongList( WrongList* p )
-{
-    mpWrongList.reset(p);
-}
-
-void ContentNode::CreateWrongList()
-{
-    SAL_WARN_IF( mpWrongList && !mpWrongList->empty(), "editeng", "WrongList 
already exist!");
-    if (!mpWrongList || !mpWrongList->empty())
-        mpWrongList.reset(new WrongList);
-}
-
-void ContentNode::DestroyWrongList()
-{
-    mpWrongList.reset();
-}
-
-void ContentNode::dumpAsXml(xmlTextWriterPtr pWriter) const
-{
-    (void)xmlTextWriterStartElement(pWriter, BAD_CAST("ContentNode"));
-    (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("maString"), 
BAD_CAST(maString.toUtf8().getStr()));
-    maContentAttribs.dumpAsXml(pWriter);
-    maCharAttribList.dumpAsXml(pWriter);
-    (void)xmlTextWriterEndElement(pWriter);
-}
-
-void ContentNode::checkAndDeleteEmptyAttribs() const
-{
-    // Delete empty attributes, but only if paragraph is not empty!
-    if (GetCharAttribs().HasEmptyAttribs() && Len())
-    {
-        const_cast<ContentNode*>(this)->GetCharAttribs().DeleteEmptyAttribs();
-    }
-}
-
-ContentAttribs::ContentAttribs( SfxItemPool& rPool )
-: mpStyle(nullptr)
-, maAttribSet( rPool )
-{
-}
-
-
-SvxTabStop ContentAttribs::FindTabStop( sal_Int32 nCurPos, sal_uInt16 nDefTab )
-{
-    const SvxTabStopItem& rTabs = GetItem( EE_PARA_TABS );
-    for ( sal_uInt16 i = 0; i < rTabs.Count(); i++ )
-    {
-        const SvxTabStop& rTab = rTabs[i];
-        if ( rTab.GetTabPos() > nCurPos  )
-            return rTab;
-    }
-
-    // if there's a default tab size defined for this item use that instead
-    if (rTabs.GetDefaultDistance())
-        nDefTab = rTabs.GetDefaultDistance();
-
-    // Determine DefTab ...
-    SvxTabStop aTabStop;
-    const sal_Int32 x = nCurPos / nDefTab + 1;
-    aTabStop.GetTabPos() = nDefTab * x;
-    return aTabStop;
-}
-
-void ContentAttribs::SetStyleSheet( SfxStyleSheet* pS )
-{
-    bool bStyleChanged = ( mpStyle != pS );
-    mpStyle = pS;
-    // Only when other style sheet, not when current style sheet modified
-    if ( !(mpStyle && bStyleChanged) )
-        return;
-
-    // Selectively remove the attributes from the paragraph formatting
-    // which are specified in the style, so that the attributes of the
-    // style can have an affect.
-    const SfxItemSet& rStyleAttribs = mpStyle->GetItemSet();
-    for ( sal_uInt16 nWhich = EE_PARA_START; nWhich <= EE_CHAR_END; nWhich++ )
-    {
-        // Don't change bullet on/off
-        if ( ( nWhich != EE_PARA_BULLETSTATE ) && ( 
rStyleAttribs.GetItemState( nWhich ) == SfxItemState::SET ) )
-            maAttribSet.ClearItem( nWhich );
-    }
-}
-
-const SfxPoolItem& ContentAttribs::GetItem( sal_uInt16 nWhich ) const
-{
-    // Hard paragraph attributes take precedence!
-    const SfxItemSet* pTakeFrom = &maAttribSet;
-    if ( mpStyle && ( maAttribSet.GetItemState( nWhich, false ) != 
SfxItemState::SET  ) )
-        pTakeFrom = &mpStyle->GetItemSet();
-
-    return pTakeFrom->Get( nWhich );
-}
-
-bool ContentAttribs::HasItem( sal_uInt16 nWhich ) const
-{
-    bool bHasItem = false;
-    if ( maAttribSet.GetItemState( nWhich, false ) == SfxItemState::SET  )
-        bHasItem = true;
-    else if ( mpStyle && mpStyle->GetItemSet().GetItemState( nWhich ) == 
SfxItemState::SET )
-        bHasItem = true;
-
-    return bHasItem;
-}
-
-void ContentAttribs::dumpAsXml(xmlTextWriterPtr pWriter) const
-{
-    (void)xmlTextWriterStartElement(pWriter, BAD_CAST("ContentAttribs"));
-    (void)xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("style"), "%s", 
mpStyle->GetName().toUtf8().getStr());
-    maAttribSet.dumpAsXml(pWriter);
-    (void)xmlTextWriterEndElement(pWriter);
-}
-
 EditDoc::EditDoc( SfxItemPool* pPool ) :
     nLastCache(0),
     pItemPool(pPool ? pPool : new EditEngineItemPool()),
@@ -2653,290 +1953,6 @@ void EditDoc::dumpAsXml(xmlTextWriterPtr pWriter) const
     }
 }
 
-
-namespace {
-
-struct LessByStart
-{
-    bool operator() (const std::unique_ptr<EditCharAttrib>& left, const 
std::unique_ptr<EditCharAttrib>& right) const
-    {
-        return left->GetStart() < right->GetStart();
-    }
-};
-
-}
-
-CharAttribList::CharAttribList()
-: mbHasEmptyAttribs(false)
-{
-}
-
-CharAttribList::~CharAttribList()
-{
-}
-
-void CharAttribList::InsertAttrib( EditCharAttrib* pAttrib )
-{
-// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-// optimize: binary search?    !
-// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-
-    // Maybe just simply iterate backwards:
-    // The most common and critical case: Attributes are already sorted
-    // (InsertTextObject!) binary search would not be optimal here.
-    // => Would bring something!
-
-    const sal_Int32 nStart = pAttrib->GetStart(); // may be better for 
Comp.Opt.
-
-#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
-    CharAttribList::DbgCheckAttribs(*this);
-#endif
-
-    if ( pAttrib->IsEmpty() )
-        mbHasEmptyAttribs = true;
-
-    bool bInsert(true);
-    for (sal_Int32 i = 0, n = maAttribs.size(); i < n; ++i)
-    {
-        const EditCharAttrib& rCurAttrib = *maAttribs[i];
-        if (rCurAttrib.GetStart() > nStart)
-        {
-            maAttribs.insert(maAttribs.begin()+i, 
std::unique_ptr<EditCharAttrib>(pAttrib));
-            bInsert = false;
-            break;
-        }
-    }
-
-    if (bInsert) maAttribs.push_back(std::unique_ptr<EditCharAttrib>(pAttrib));
-
-#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
-    CharAttribList::DbgCheckAttribs(*this);
-#endif
-}
-
-void CharAttribList::ResortAttribs()
-{
-    std::sort(maAttribs.begin(), maAttribs.end(), LessByStart());
-
-#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
-    CharAttribList::DbgCheckAttribs(*this);
-#endif
-}
-
-void CharAttribList::OptimizeRanges()
-{
-#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
-    CharAttribList::DbgCheckAttribs(*this);
-#endif
-    for (sal_Int32 i = 0; i < static_cast<sal_Int32>(maAttribs.size()); ++i)
-    {
-        EditCharAttrib& rAttr = *maAttribs[i];
-        for (sal_Int32 nNext = i+1; nNext < 
static_cast<sal_Int32>(maAttribs.size()); ++nNext)
-        {
-            EditCharAttrib& rNext = *maAttribs[nNext];
-            if (!rAttr.IsFeature() && rNext.GetStart() == rAttr.GetEnd() && 
rNext.Which() == rAttr.Which())
-            {
-                if (*rNext.GetItem() == *rAttr.GetItem())
-                {
-                    rAttr.GetEnd() = rNext.GetEnd();
-                    maAttribs.erase(maAttribs.begin()+nNext);
-                }
-                break;  // only 1 attr with same which can start here.
-            }
-            else if (rNext.GetStart() > rAttr.GetEnd())
-            {
-                break;
-            }
-        }
-    }
-#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
-    CharAttribList::DbgCheckAttribs(*this);
-#endif
-}
-
-sal_Int32 CharAttribList::Count() const
-{
-    return maAttribs.size();
-}
-
-const EditCharAttrib* CharAttribList::FindAttrib( sal_uInt16 nWhich, sal_Int32 
nPos ) const
-{
-    // Backwards, if one ends where the next starts.
-    // => The starting one is the valid one ...
-    AttribsType::const_reverse_iterator it = std::find_if(maAttribs.rbegin(), 
maAttribs.rend(),
-        [&nWhich, &nPos](const AttribsType::value_type& rxAttr) {
-            return rxAttr->Which() == nWhich && rxAttr->IsIn(nPos); });
-    if (it != maAttribs.rend())
-    {
-        const EditCharAttrib& rAttr = **it;
-        return &rAttr;
-    }
-    return nullptr;
-}
-
-EditCharAttrib* CharAttribList::FindAttrib( sal_uInt16 nWhich, sal_Int32 nPos )
-{
-    // Backwards, if one ends where the next starts.
-    // => The starting one is the valid one ...
-    AttribsType::reverse_iterator it = std::find_if(maAttribs.rbegin(), 
maAttribs.rend(),
-        [&nWhich, &nPos](AttribsType::value_type& rxAttr) {
-            return rxAttr->Which() == nWhich && rxAttr->IsIn(nPos); });
-    if (it != maAttribs.rend())
-    {
-        EditCharAttrib& rAttr = **it;
-        return &rAttr;
-    }
-    return nullptr;
-}
-
-const EditCharAttrib* CharAttribList::FindNextAttrib( sal_uInt16 nWhich, 
sal_Int32 nFromPos ) const
-{
-    assert(nWhich);
-    for (auto const& attrib : maAttribs)
-    {
-        const EditCharAttrib& rAttr = *attrib;
-        if (rAttr.GetStart() >= nFromPos && rAttr.Which() == nWhich)
-            return &rAttr;
-    }
-    return nullptr;
-}
-
-bool CharAttribList::HasAttrib( sal_Int32 nStartPos, sal_Int32 nEndPos ) const
-{
-    return std::any_of(maAttribs.rbegin(), maAttribs.rend(),
-        [&nStartPos, &nEndPos](const AttribsType::value_type& rxAttr) {
-            return rxAttr->GetStart() < nEndPos && rxAttr->GetEnd() > 
nStartPos; });
-}
-
-
-namespace {
-
-class FindByAddress
-{
-    const EditCharAttrib* mpAttr;
-public:
-    explicit FindByAddress(const EditCharAttrib* p) : mpAttr(p) {}
-    bool operator() (const std::unique_ptr<EditCharAttrib>& r) const
-    {
-        return r.get() == mpAttr;
-    }
-};
-
-}
-
-void CharAttribList::Remove(const EditCharAttrib* p)
-{
-    AttribsType::iterator it = std::find_if(maAttribs.begin(), 
maAttribs.end(), FindByAddress(p));
-    if (it != maAttribs.end())
-        maAttribs.erase(it);
-}
-
-void CharAttribList::Remove(sal_Int32 nPos)
-{
-    if (nPos >= static_cast<sal_Int32>(maAttribs.size()))
-        return;
-
-    maAttribs.erase(maAttribs.begin()+nPos);
-}
-
-void CharAttribList::SetHasEmptyAttribs(bool b)
-{
-    mbHasEmptyAttribs = b;
-}
-
-bool CharAttribList::HasBoundingAttrib( sal_Int32 nBound ) const
-{
-    // Backwards, if one ends where the next starts.
-    // => The starting one is the valid one ...
-    AttribsType::const_reverse_iterator it = maAttribs.rbegin(), itEnd = 
maAttribs.rend();
-    for (; it != itEnd; ++it)
-    {
-        const EditCharAttrib& rAttr = **it;
-        if (rAttr.GetEnd() < nBound)
-            return false;
-
-        if (rAttr.GetStart() == nBound || rAttr.GetEnd() == nBound)
-            return true;
-    }
-    return false;
-}
-
-EditCharAttrib* CharAttribList::FindEmptyAttrib( sal_uInt16 nWhich, sal_Int32 
nPos )
-{
-    if ( !mbHasEmptyAttribs )
-        return nullptr;
-
-    for (const std::unique_ptr<EditCharAttrib>& rAttr : maAttribs)
-    {
-        if (rAttr->GetStart() == nPos && rAttr->GetEnd() == nPos && 
rAttr->Which() == nWhich)
-            return rAttr.get();
-    }
-    return nullptr;
-}
-
-namespace {
-
-class FindByStartPos
-{
-    sal_Int32 mnPos;
-public:
-    explicit FindByStartPos(sal_Int32 nPos) : mnPos(nPos) {}
-    bool operator() (const std::unique_ptr<EditCharAttrib>& r) const
-    {
-        return r->GetStart() >= mnPos;
-    }
-};
-
-}
-
-const EditCharAttrib* CharAttribList::FindFeature( sal_Int32 nPos ) const
-{
-    // First, find the first attribute that starts at or after specified 
position.
-    AttribsType::const_iterator it =
-        std::find_if(maAttribs.begin(), maAttribs.end(), FindByStartPos(nPos));
-
-    if (it == maAttribs.end())
-        // All attributes are before the specified position.
-        return nullptr;
-
-    // And find the first attribute with feature.
-    it = std::find_if(it, maAttribs.end(), [](const 
std::unique_ptr<EditCharAttrib>& aAttrib) { return aAttrib->IsFeature(); } );
-    return it == maAttribs.end() ? nullptr : it->get();
-}
-
-void CharAttribList::DeleteEmptyAttribs()
-{
-    std::erase_if(maAttribs, [](const std::unique_ptr<EditCharAttrib>& 
aAttrib) { return aAttrib->IsEmpty(); } );
-    mbHasEmptyAttribs = false;
-}
-
-#if OSL_DEBUG_LEVEL > 0 && !defined NDEBUG
-void CharAttribList::DbgCheckAttribs(CharAttribList const& rAttribs)
-{
-    std::set<std::pair<sal_Int32, sal_uInt16>> zero_set;
-    for (const std::unique_ptr<EditCharAttrib>& rAttr : rAttribs.maAttribs)
-    {
-        assert(rAttr->GetStart() <= rAttr->GetEnd());
-        assert(!rAttr->IsFeature() || rAttr->GetLen() == 1);
-        if (0 == rAttr->GetLen())
-        {
-            // not sure if 0-length attributes allowed at all in non-empty 
para?
-            assert(zero_set.insert(std::make_pair(rAttr->GetStart(), 
rAttr->Which())).second && "duplicate 0-length attribute detected");
-        }
-    }
-    CheckOrderedList(rAttribs.GetAttribs());
-}
-#endif
-
-void CharAttribList::dumpAsXml(xmlTextWriterPtr pWriter) const
-{
-    (void)xmlTextWriterStartElement(pWriter, BAD_CAST("CharAttribList"));
-    for (auto const & i : maAttribs) {
-        i->dumpAsXml(pWriter);
-    }
-    (void)xmlTextWriterEndElement(pWriter);
-}
-
 EditEngineItemPool::EditEngineItemPool()
     : SfxItemPool( "EditEngineItemPool", EE_ITEMS_START, EE_ITEMS_END,
                     aItemInfos, nullptr )
diff --git a/solenv/clang-format/excludelist b/solenv/clang-format/excludelist
index 232b346921d1..045161b84bd1 100644
--- a/solenv/clang-format/excludelist
+++ b/solenv/clang-format/excludelist
@@ -3386,6 +3386,7 @@ editeng/source/accessibility/AccessibleParaManager.cxx
 editeng/source/accessibility/AccessibleSelectionBase.cxx
 editeng/source/accessibility/AccessibleStaticTextBase.cxx
 editeng/source/accessibility/AccessibleStringWrap.cxx
+editeng/source/editeng/ContentNode.cxx
 editeng/source/editeng/editattr.cxx
 editeng/source/editeng/editdbg.cxx
 editeng/source/editeng/editdoc.cxx

Reply via email to