sw/CppunitTest_sw_core_doc.mk                 |    1 
 sw/qa/core/doc/DocumentRedlineManager.cxx     |   72 ++++
 sw/qa/core/doc/data/ins.docx                  |binary
 sw/source/core/doc/DocumentRedlineManager.cxx |  431 +++++++++++++-------------
 sw/source/core/inc/DocumentRedlineManager.hxx |    2 
 5 files changed, 301 insertions(+), 205 deletions(-)

New commits:
commit eef0dfed817e40cd83e8ba8e290f45c224257f97
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Thu Jun 12 09:02:52 2025 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Jun 12 19:38:58 2025 +0200

    tdf#166319 sw interdependent redlines: add UI to create format inside insert
    
    The bugdoc has <ins>AABBCC</ins> in it, selecting BB and pressing e.g.
    bold simply applied the formatting without creating a redline, even if
    the change is from another user.
    
    This was working for the case when a delete redline is created on top of
    an insert one, but was broken for insert-then-format: simply code was
    missing to try to handle the non-IsOwnRedline() case.
    
    Fix the problem by extracting this "split existing redline as necessary,
    then turn the overlapping range into a hierarchical redline" logic from
    sw::DocumentRedlineManager::PreAppendDeleteRedline() into a new
    PreAppendForeignRedline(), and next to the old insert-then-delete case,
    also use it for insert-then-format and delete-then-format.
    
    The new PreAppendForeignRedline() has a single part where it deals with
    moves for insert-then-delete, disable that for insert-then-format, since
    that's not relevant. Undo still needs to be fixed. Finally keep the
    logic unchanged the own delete/insert + own format redline case for now,
    we want different behavior for insert-then-delete and insert-then-format
    in this case, so intentionally not sharing that.
    
    Change-Id: Ifd2903f39d92a1bee96de0a38976eb5111c49223
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/186423
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/sw/CppunitTest_sw_core_doc.mk b/sw/CppunitTest_sw_core_doc.mk
index ebd8db9d0781..9e12126c1c7a 100644
--- a/sw/CppunitTest_sw_core_doc.mk
+++ b/sw/CppunitTest_sw_core_doc.mk
@@ -15,6 +15,7 @@ $(eval $(call 
gb_CppunitTest_use_common_precompiled_header,sw_core_doc))
 
 $(eval $(call gb_CppunitTest_add_exception_objects,sw_core_doc, \
     sw/qa/core/doc/doc \
+    sw/qa/core/doc/DocumentRedlineManager \
 ))
 
 $(eval $(call gb_CppunitTest_use_libraries,sw_core_doc, \
diff --git a/sw/qa/core/doc/DocumentRedlineManager.cxx 
b/sw/qa/core/doc/DocumentRedlineManager.cxx
new file mode 100644
index 000000000000..699b1f61570e
--- /dev/null
+++ b/sw/qa/core/doc/DocumentRedlineManager.cxx
@@ -0,0 +1,72 @@
+/* -*- 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/.
+ */
+
+#include <swmodeltestbase.hxx>
+
+#include <editeng/wghtitem.hxx>
+
+#include <IDocumentRedlineAccess.hxx>
+#include <docsh.hxx>
+#include <redline.hxx>
+#include <view.hxx>
+#include <wrtsh.hxx>
+
+namespace
+{
+/// Covers sw/source/core/doc/DocumentRedlineManager.cxx fixes.
+class Test : public SwModelTestBase
+{
+public:
+    Test()
+        : SwModelTestBase(u"/sw/qa/core/doc/data/"_ustr)
+    {
+    }
+};
+
+CPPUNIT_TEST_FIXTURE(Test, testRedlineIns)
+{
+    // Given a document with an insert redline:
+    createSwDoc("ins.docx");
+
+    // When selecting BBB (a subset of the insert) and marking that as bold:
+    SwDocShell* pDocShell = getSwDocShell();
+    SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
+    pWrtShell->SttEndDoc(/*bStt=*/true);
+    pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 3, 
/*bBasicCall=*/false);
+    pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 3, 
/*bBasicCall=*/false);
+    SwView& rView = pWrtShell->GetView();
+    {
+        SvxWeightItem aWeightItem(WEIGHT_BOLD, RES_CHRATR_WEIGHT);
+        SfxItemSetFixed<RES_CHRATR_BEGIN, RES_CHRATR_END> 
aSet(rView.GetPool());
+        aSet.Put(aWeightItem);
+        pWrtShell->SetAttrSet(aSet);
+    }
+
+    // Then make sure BBB is covered by an insert-then-format redline:
+    SwDoc* pDoc = getSwDocShell()->GetDoc();
+    IDocumentRedlineAccess& rIDRA = pDoc->getIDocumentRedlineAccess();
+    SwRedlineTable& rRedlines = rIDRA.GetRedlineTable();
+    {
+        // Without the accompanying fix in place, this test would have failed 
with:
+        // - Expected: 1
+        // - Actual  : 3
+        // i.e. no redline was created for the format change.
+        CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), rRedlines.size());
+        CPPUNIT_ASSERT_EQUAL(RedlineType::Insert, rRedlines[0]->GetType());
+        const SwRedlineData& rRedlineData1 = rRedlines[1]->GetRedlineData(0);
+        CPPUNIT_ASSERT_EQUAL(RedlineType::Format, rRedlineData1.GetType());
+        CPPUNIT_ASSERT(rRedlineData1.Next());
+        const SwRedlineData& rInnerRedlineData = *rRedlineData1.Next();
+        CPPUNIT_ASSERT_EQUAL(RedlineType::Insert, rInnerRedlineData.GetType());
+        CPPUNIT_ASSERT_EQUAL(RedlineType::Insert, rRedlines[2]->GetType());
+    }
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/core/doc/data/ins.docx b/sw/qa/core/doc/data/ins.docx
new file mode 100644
index 000000000000..9460aa306716
Binary files /dev/null and b/sw/qa/core/doc/data/ins.docx differ
diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx 
b/sw/source/core/doc/DocumentRedlineManager.cxx
index 54127a714826..95d472dfb341 100644
--- a/sw/source/core/doc/DocumentRedlineManager.cxx
+++ b/sw/source/core/doc/DocumentRedlineManager.cxx
@@ -1487,6 +1487,171 @@ public:
     std::set<sal_uInt32>& deletedMoveIDs;
 };
 
+void DocumentRedlineManager::PreAppendForeignRedline(AppendRedlineContext& 
rCtx)
+{
+    // it may be necessary to split the existing redline in
+    // two. In this case, pRedl will be changed to cover
+    // only part of its former range, and pNew will cover
+    // the remainder.
+    SwRangeRedline* pNew = nullptr;
+
+    switch( rCtx.eCmpPos )
+    {
+    case SwComparePosition::Equal:
+        {
+            rCtx.pRedl->PushData( *rCtx.pNewRedl );
+            delete rCtx.pNewRedl;
+            rCtx.pNewRedl = nullptr;
+            if( IsHideChanges( GetRedlineFlags() ))
+            {
+                rCtx.pRedl->Hide(0, maRedlineTable.GetPos(rCtx.pRedl));
+            }
+            rCtx.bCompress = true;
+
+            if (rCtx.pNewRedl && rCtx.pNewRedl->GetType() == 
RedlineType::Delete)
+            {
+                // set IsMoved checking nearby redlines
+                SwRedlineTable::size_type nRIdx = 
maRedlineTable.GetPos(rCtx.pRedl);
+                if (nRIdx < maRedlineTable.size()) // in case above 
're-insert' failed
+                    maRedlineTable.isMoved(nRIdx);
+            }
+
+        }
+        break;
+
+    case SwComparePosition::Inside:
+        {
+            if( *rCtx.pRStt == *rCtx.pStart )
+            {
+                // #i97421#
+                // redline w/out extent loops
+                if (*rCtx.pStart != *rCtx.pEnd)
+                {
+                    rCtx.pNewRedl->PushData( *rCtx.pRedl, false );
+                    rCtx.pRedl->SetStart( *rCtx.pEnd, rCtx.pRStt );
+                    // re-insert
+                    maRedlineTable.Remove( rCtx.n );
+                    maRedlineTable.Insert( rCtx.pRedl, rCtx.n );
+                    rCtx.bDec = true;
+                }
+            }
+            else
+            {
+                rCtx.pNewRedl->PushData( *rCtx.pRedl, false );
+                if( *rCtx.pREnd != *rCtx.pEnd )
+                {
+                    pNew = new SwRangeRedline( *rCtx.pRedl );
+                    pNew->SetStart( *rCtx.pEnd );
+                }
+                rCtx.pRedl->SetEnd( *rCtx.pStart, rCtx.pREnd );
+                if( !rCtx.pRedl->HasValidRange() )
+                {
+                    // re-insert
+                    maRedlineTable.Remove( rCtx.n );
+                    maRedlineTable.Insert( rCtx.pRedl, rCtx.n );
+                }
+            }
+        }
+        break;
+
+    case SwComparePosition::Outside:
+        {
+            rCtx.pRedl->PushData( *rCtx.pNewRedl );
+            if( *rCtx.pEnd == *rCtx.pREnd )
+            {
+                rCtx.pNewRedl->SetEnd( *rCtx.pRStt, rCtx.pEnd );
+            }
+            else if (*rCtx.pStart == *rCtx.pRStt)
+            {
+                rCtx.pNewRedl->SetStart(*rCtx.pREnd, rCtx.pStart);
+            }
+            else
+            {
+                pNew = new SwRangeRedline( *rCtx.pNewRedl );
+                pNew->SetEnd( *rCtx.pRStt );
+                rCtx.pNewRedl->SetStart( *rCtx.pREnd, rCtx.pStart );
+            }
+            rCtx.bCompress = true;
+        }
+        break;
+
+    case SwComparePosition::OverlapBefore:
+        {
+            if( *rCtx.pEnd == *rCtx.pREnd )
+            {
+                rCtx.pRedl->PushData( *rCtx.pNewRedl );
+                rCtx.pNewRedl->SetEnd( *rCtx.pRStt, rCtx.pEnd );
+                if( IsHideChanges( GetRedlineFlags() ))
+                {
+                    maRedlineTable.Insert(rCtx.pNewRedl);
+                    rCtx.pRedl->Hide(0, maRedlineTable.GetPos(rCtx.pRedl));
+                    maRedlineTable.Remove( rCtx.pNewRedl );
+                }
+            }
+            else
+            {
+                pNew = new SwRangeRedline( *rCtx.pRedl );
+                pNew->PushData( *rCtx.pNewRedl );
+                pNew->SetEnd( *rCtx.pEnd );
+                rCtx.pNewRedl->SetEnd( *rCtx.pRStt, rCtx.pEnd );
+                rCtx.pRedl->SetStart( *pNew->End(), rCtx.pRStt ) ;
+                // re-insert
+                maRedlineTable.Remove( rCtx.n );
+                maRedlineTable.Insert( rCtx.pRedl );
+                rCtx.bDec = true;
+            }
+        }
+        break;
+
+    case SwComparePosition::OverlapBehind:
+        {
+            if( *rCtx.pStart == *rCtx.pRStt )
+            {
+                rCtx.pRedl->PushData( *rCtx.pNewRedl );
+                rCtx.pNewRedl->SetStart( *rCtx.pREnd, rCtx.pStart );
+                if( IsHideChanges( GetRedlineFlags() ))
+                {
+                    maRedlineTable.Insert( rCtx.pNewRedl );
+                    rCtx.pRedl->Hide(0, maRedlineTable.GetPos(rCtx.pRedl));
+                    maRedlineTable.Remove( rCtx.pNewRedl );
+                }
+            }
+            else
+            {
+                pNew = new SwRangeRedline( *rCtx.pRedl );
+                pNew->PushData( *rCtx.pNewRedl );
+                pNew->SetStart( *rCtx.pStart );
+                rCtx.pNewRedl->SetStart( *rCtx.pREnd, rCtx.pStart );
+                rCtx.pRedl->SetEnd( *pNew->Start(), rCtx.pREnd );
+                if( !rCtx.pRedl->HasValidRange() )
+                {
+                    // re-insert
+                    maRedlineTable.Remove( rCtx.n );
+                    maRedlineTable.Insert( rCtx.pRedl );
+                }
+            }
+        }
+        break;
+    default:
+        break;
+    }
+
+    // insert the pNew part (if it exists)
+    if( pNew )
+    {
+        maRedlineTable.Insert( pNew );
+
+        // pNew must be deleted if Insert() wasn't
+        // successful. But that can't happen, since pNew is
+        // part of the original pRedl redline.
+        // OSL_ENSURE( bRet, "Can't insert existing redline?" );
+
+        // restart (now with pRedl being split up)
+        rCtx.n = 0;
+        rCtx.bDec = true;
+    }
+}
+
 void DocumentRedlineManager::PreAppendInsertRedline(AppendRedlineContext& rCtx)
 {
     switch( rCtx.pRedl->GetType() )
@@ -1993,164 +2158,7 @@ void 
DocumentRedlineManager::PreAppendDeleteRedline(AppendRedlineContext& rCtx)
         }
         else
         {
-            // it may be necessary to split the existing redline in
-            // two. In this case, pRedl will be changed to cover
-            // only part of its former range, and pNew will cover
-            // the remainder.
-            SwRangeRedline* pNew = nullptr;
-
-            switch( rCtx.eCmpPos )
-            {
-            case SwComparePosition::Equal:
-                {
-                    rCtx.pRedl->PushData( *rCtx.pNewRedl );
-                    delete rCtx.pNewRedl;
-                    rCtx.pNewRedl = nullptr;
-                    if( IsHideChanges( GetRedlineFlags() ))
-                    {
-                        rCtx.pRedl->Hide(0, maRedlineTable.GetPos(rCtx.pRedl));
-                    }
-                    rCtx.bCompress = true;
-
-                    // set IsMoved checking nearby redlines
-                    SwRedlineTable::size_type nRIdx = 
maRedlineTable.GetPos(rCtx.pRedl);
-                    if (nRIdx < maRedlineTable.size()) // in case above 
're-insert' failed
-                        maRedlineTable.isMoved(nRIdx);
-
-                }
-                break;
-
-            case SwComparePosition::Inside:
-                {
-                    if( *rCtx.pRStt == *rCtx.pStart )
-                    {
-                        // #i97421#
-                        // redline w/out extent loops
-                        if (*rCtx.pStart != *rCtx.pEnd)
-                        {
-                            rCtx.pNewRedl->PushData( *rCtx.pRedl, false );
-                            rCtx.pRedl->SetStart( *rCtx.pEnd, rCtx.pRStt );
-                            // re-insert
-                            maRedlineTable.Remove( rCtx.n );
-                            maRedlineTable.Insert( rCtx.pRedl, rCtx.n );
-                            rCtx.bDec = true;
-                        }
-                    }
-                    else
-                    {
-                        rCtx.pNewRedl->PushData( *rCtx.pRedl, false );
-                        if( *rCtx.pREnd != *rCtx.pEnd )
-                        {
-                            pNew = new SwRangeRedline( *rCtx.pRedl );
-                            pNew->SetStart( *rCtx.pEnd );
-                        }
-                        rCtx.pRedl->SetEnd( *rCtx.pStart, rCtx.pREnd );
-                        if( !rCtx.pRedl->HasValidRange() )
-                        {
-                            // re-insert
-                            maRedlineTable.Remove( rCtx.n );
-                            maRedlineTable.Insert( rCtx.pRedl, rCtx.n );
-                        }
-                    }
-                }
-                break;
-
-            case SwComparePosition::Outside:
-                {
-                    rCtx.pRedl->PushData( *rCtx.pNewRedl );
-                    if( *rCtx.pEnd == *rCtx.pREnd )
-                    {
-                        rCtx.pNewRedl->SetEnd( *rCtx.pRStt, rCtx.pEnd );
-                    }
-                    else if (*rCtx.pStart == *rCtx.pRStt)
-                    {
-                        rCtx.pNewRedl->SetStart(*rCtx.pREnd, rCtx.pStart);
-                    }
-                    else
-                    {
-                        pNew = new SwRangeRedline( *rCtx.pNewRedl );
-                        pNew->SetEnd( *rCtx.pRStt );
-                        rCtx.pNewRedl->SetStart( *rCtx.pREnd, rCtx.pStart );
-                    }
-                    rCtx.bCompress = true;
-                }
-                break;
-
-            case SwComparePosition::OverlapBefore:
-                {
-                    if( *rCtx.pEnd == *rCtx.pREnd )
-                    {
-                        rCtx.pRedl->PushData( *rCtx.pNewRedl );
-                        rCtx.pNewRedl->SetEnd( *rCtx.pRStt, rCtx.pEnd );
-                        if( IsHideChanges( GetRedlineFlags() ))
-                        {
-                            maRedlineTable.Insert(rCtx.pNewRedl);
-                            rCtx.pRedl->Hide(0, 
maRedlineTable.GetPos(rCtx.pRedl));
-                            maRedlineTable.Remove( rCtx.pNewRedl );
-                        }
-                    }
-                    else
-                    {
-                        pNew = new SwRangeRedline( *rCtx.pRedl );
-                        pNew->PushData( *rCtx.pNewRedl );
-                        pNew->SetEnd( *rCtx.pEnd );
-                        rCtx.pNewRedl->SetEnd( *rCtx.pRStt, rCtx.pEnd );
-                        rCtx.pRedl->SetStart( *pNew->End(), rCtx.pRStt ) ;
-                        // re-insert
-                        maRedlineTable.Remove( rCtx.n );
-                        maRedlineTable.Insert( rCtx.pRedl );
-                        rCtx.bDec = true;
-                    }
-                }
-                break;
-
-            case SwComparePosition::OverlapBehind:
-                {
-                    if( *rCtx.pStart == *rCtx.pRStt )
-                    {
-                        rCtx.pRedl->PushData( *rCtx.pNewRedl );
-                        rCtx.pNewRedl->SetStart( *rCtx.pREnd, rCtx.pStart );
-                        if( IsHideChanges( GetRedlineFlags() ))
-                        {
-                            maRedlineTable.Insert( rCtx.pNewRedl );
-                            rCtx.pRedl->Hide(0, 
maRedlineTable.GetPos(rCtx.pRedl));
-                            maRedlineTable.Remove( rCtx.pNewRedl );
-                        }
-                    }
-                    else
-                    {
-                        pNew = new SwRangeRedline( *rCtx.pRedl );
-                        pNew->PushData( *rCtx.pNewRedl );
-                        pNew->SetStart( *rCtx.pStart );
-                        rCtx.pNewRedl->SetStart( *rCtx.pREnd, rCtx.pStart );
-                        rCtx.pRedl->SetEnd( *pNew->Start(), rCtx.pREnd );
-                        if( !rCtx.pRedl->HasValidRange() )
-                        {
-                            // re-insert
-                            maRedlineTable.Remove( rCtx.n );
-                            maRedlineTable.Insert( rCtx.pRedl );
-                        }
-                    }
-                }
-                break;
-            default:
-                break;
-            }
-
-            // insert the pNew part (if it exists)
-            if( pNew )
-            {
-                maRedlineTable.Insert( pNew );
-
-                // pNew must be deleted if Insert() wasn't
-                // successful. But that can't happen, since pNew is
-                // part of the original pRedl redline.
-                // OSL_ENSURE( bRet, "Can't insert existing redline?" );
-
-                // restart (now with pRedl being split up)
-                rCtx.n = 0;
-                rCtx.bDec = true;
-            }
+            PreAppendForeignRedline(rCtx);
         }
     }
     break;
@@ -2214,61 +2222,74 @@ void 
DocumentRedlineManager::PreAppendFormatRedline(AppendRedlineContext& rCtx)
     {
     case RedlineType::Insert:
     case RedlineType::Delete:
-        switch( rCtx.eCmpPos )
+    {
+        RedlineFlags eOld = GetRedlineFlags();
+        bool bCombineRedlines = !(eOld & RedlineFlags::DontCombineRedlines)
+                                && rCtx.pRedl->IsOwnRedline(*rCtx.pNewRedl)
+                                && 
!rCtx.pRedl->GetRedlineData(0).IsAnonymized();
+        if (bCombineRedlines || rCtx.pRedl->IsMoved())
         {
-        case SwComparePosition::OverlapBefore:
-            rCtx.pNewRedl->SetEnd( *rCtx.pRStt, rCtx.pEnd );
-            break;
-
-        case SwComparePosition::OverlapBehind:
-            rCtx.pNewRedl->SetStart( *rCtx.pREnd, rCtx.pStart );
-            break;
+            switch( rCtx.eCmpPos )
+            {
+            case SwComparePosition::OverlapBefore:
+                rCtx.pNewRedl->SetEnd( *rCtx.pRStt, rCtx.pEnd );
+                break;
 
-        case SwComparePosition::Inside:
-            if (*rCtx.pRStt < *rCtx.pStart && *rCtx.pREnd == *rCtx.pEnd)
-            {
-                // pRedl start is before pNewRedl start, the ends match: then 
create the
-                // format on top of insert/delete & reduce the end of the 
original
-                // insert/delete to avoid an overlap.
-                rCtx.pNewRedl->PushData(*rCtx.pRedl, false);
-                rCtx.pRedl->SetEnd(*rCtx.pStart);
-                rCtx.n = 0;
-                rCtx.bDec = true;
+            case SwComparePosition::OverlapBehind:
+                rCtx.pNewRedl->SetStart( *rCtx.pREnd, rCtx.pStart );
                 break;
-            }
-            [[fallthrough]];
-        case SwComparePosition::Equal:
-            delete rCtx.pNewRedl;
-            rCtx.pNewRedl = nullptr;
 
-            MaybeNotifyRedlineModification(*rCtx.pRedl, m_rDoc);
-            break;
+            case SwComparePosition::Inside:
+                if (*rCtx.pRStt < *rCtx.pStart && *rCtx.pREnd == *rCtx.pEnd)
+                {
+                    // pRedl start is before pNewRedl start, the ends match: 
then create the
+                    // format on top of insert/delete & reduce the end of the 
original
+                    // insert/delete to avoid an overlap.
+                    rCtx.pNewRedl->PushData(*rCtx.pRedl, false);
+                    rCtx.pRedl->SetEnd(*rCtx.pStart);
+                    rCtx.n = 0;
+                    rCtx.bDec = true;
+                    break;
+                }
+                [[fallthrough]];
+            case SwComparePosition::Equal:
+                delete rCtx.pNewRedl;
+                rCtx.pNewRedl = nullptr;
 
-        case SwComparePosition::Outside:
-            // Overlaps the current one completely,
-            // split or shorten the new one
-            if (*rCtx.pEnd == *rCtx.pREnd)
-            {
-                rCtx.pNewRedl->SetEnd(*rCtx.pRStt, rCtx.pEnd);
-            }
-            else if (*rCtx.pStart == *rCtx.pRStt)
-            {
-                rCtx.pNewRedl->SetStart(*rCtx.pREnd, rCtx.pStart);
-            }
-            else
-            {
-                SwRangeRedline* pNew = new SwRangeRedline( *rCtx.pNewRedl );
-                pNew->SetStart( *rCtx.pREnd );
-                rCtx.pNewRedl->SetEnd( *rCtx.pRStt, rCtx.pEnd );
-                AppendRedline( pNew, rCtx.bCallDelete );
-                rCtx.n = 0;      // re-initialize
-                rCtx.bDec = true;
+                MaybeNotifyRedlineModification(*rCtx.pRedl, m_rDoc);
+                break;
+
+            case SwComparePosition::Outside:
+                // Overlaps the current one completely,
+                // split or shorten the new one
+                if (*rCtx.pEnd == *rCtx.pREnd)
+                {
+                    rCtx.pNewRedl->SetEnd(*rCtx.pRStt, rCtx.pEnd);
+                }
+                else if (*rCtx.pStart == *rCtx.pRStt)
+                {
+                    rCtx.pNewRedl->SetStart(*rCtx.pREnd, rCtx.pStart);
+                }
+                else
+                {
+                    SwRangeRedline* pNew = new SwRangeRedline( *rCtx.pNewRedl 
);
+                    pNew->SetStart( *rCtx.pREnd );
+                    rCtx.pNewRedl->SetEnd( *rCtx.pRStt, rCtx.pEnd );
+                    AppendRedline( pNew, rCtx.bCallDelete );
+                    rCtx.n = 0;      // re-initialize
+                    rCtx.bDec = true;
+                }
+                break;
+            default:
+                break;
             }
-            break;
-        default:
-            break;
+        }
+        else
+        {
+            PreAppendForeignRedline(rCtx);
         }
         break;
+    }
     case RedlineType::Format:
         switch( rCtx.eCmpPos )
         {
diff --git a/sw/source/core/inc/DocumentRedlineManager.hxx 
b/sw/source/core/inc/DocumentRedlineManager.hxx
index 817861b0fbbd..bc4187406dc0 100644
--- a/sw/source/core/inc/DocumentRedlineManager.hxx
+++ b/sw/source/core/inc/DocumentRedlineManager.hxx
@@ -168,6 +168,8 @@ private:
     void PreAppendInsertRedline(AppendRedlineContext& rCtx);
     void PreAppendDeleteRedline(AppendRedlineContext& rCtx);
     void PreAppendFormatRedline(AppendRedlineContext& rCtx);
+    /// Append a next redline partially on top of another existing redline.
+    void PreAppendForeignRedline(AppendRedlineContext& rCtx);
 
     DocumentRedlineManager(DocumentRedlineManager const&) = delete;
     DocumentRedlineManager& operator=(DocumentRedlineManager const&) = delete;

Reply via email to